
    ҋiJ                     8   d Z ddlZddlZddlZddlZddlmZmZ ddlmZ ddl	m
Z
mZmZmZmZ ddlmZmZmZmZmZ ddlmZ 	 ddlmZ  ee      j6                  d	z  ZdAd
ededefdZdedefdZ dBded
ededefdZ!	 dBdeee
f   dededefdZ"dedee   fdZ#deee
f   defdZ$dBdedefdZ%dBdedefdZ&dBdeee
f   dedefdZ'dCdedededeeee
f   e(f   fdZ)	 	 	 dDdeee
f   ded ed!edeee
f   f
d"Z*deee
f   deee
f   fd#Z+	 dEdeee
f   deee
f   d$e,deee
f   fd%Z-dFdededeee
f   fd&Z.	 	 	 dGdeee
f   ded ed(edeee
f   f
d)Z/	 	 dHdeee
f   ded*edeee
f   fd+Z0	 	 dHdeee
f   d,eee
f   ded*edeee
f   f
d-Z1	 dIdeee
f   deee
f   d*edeee
f   fd.Z2	 	 dJdeee
f   d,eee
f   ded*edeee
f   f
d/Z3	 dKdeee
f   d0eee
f   d*edeee
f   fd1Z4	 	 dHdeee
f   ded*edeee
f   fd2Z5	 	 	 dLdeee
f   ded*ed edeee
f   f
d4Z6	 	 	 	 	 dMdeee
f   ded5ed*ed6e,d edeee
f   fd7Z7e8d8k(  rddl9Z9 ee      j6                  d	z  d9z  Z:e:jw                         s e<d:e:         e9jz                  d;        e>e:d<      5 Z? ej                  e?      ZAddd        e7eAdd3d=      ZB e>e:d>      5 Z? ej                  eBe?d'?       ddd        e<d@e:        yy# e$ r dZY w xY w# 1 sw Y   WxY w# 1 sw Y   0xY w)Nu  
Video Generation Pipeline - Layers 4

v1/v2/v3 (Legacy): 4a (concepts) → 4b (script/production_spec) → 4c (visuals/assets)
v4 (Current): Director → Evaluator → (Revise if needed) → Production Ready

The v4 architecture uses:
- Script Director (Opus): Takes premise + research → produces time-coded multi-track script
- Script Evaluator (Opus): Evaluates script against cognitive science criteria → verdict + revision instructions
- Max 1 revision iteration if not PRODUCTION_READY
    N)datetimetimezone)Path)AnyDictListOptionalTuple)
get_promptget_prompt_metadataget_revision_templateget_channel_director_promptCHANNEL_SPECIFIC_DIRECTORS)'update_opportunity_video_gen_by_cluster)get_channeloutputpremise
max_lengthreturnc                    | j                         }h d}t        j                  dd|      }|j                         D cg c]  }|s||vs| }}t	        |      dk  rGt        j                  dd| j                               j                         D cg c]  }|s|	 c}dd }dj                  |      }t	        |      |kD  r|d| j                  dd      d	   }|xs d
S c c}w c c}w )u$  
    Convert a premise string to a safe filename component.

    Examples:
        "The Tobacco Company That Bought the Women's Movement"
        → "tobacco-company-bought-womens-movement"

        "Why You Can't Stop Checking Your Phone"
        → "why-you-cant-stop-checking-phone"
    >   aanatbebydoinisitnoofonorsotoupallandanyarebadbigbutcandidforhadhashowitslowmaynewnotnowoffoldoneoutownthetootwowaswhyyesyetalsoawaybackbeenbothdoesdowneachevenfromgoodhaveherehighintojustlastlesslongmanymoremostmuchmustnoneonceonlyoversamesomethanthatthenthistrueverywellwerewhenwillwithaboutafteragainbeingcouldeveryfalsefirstgreatleastmaybemightneveroftenotherrightshallshortsmallstilltherethreeunderwherewouldwrongalwaysbeforeduringeitherlittlereallyshouldbetweenneitherperhapsthroughusuallywithoutactuallyprobably	sometimesz[^a-z0-9\s]    N   -   r   untitled)lowerresubsplitlenjoinrsplit)r   r   name	stopwordswwordss         :/home/sietch6/trending-topics-pipeline/video_generation.pysanitize_premise_for_filenamer   (   s     ==?D hI 66.#t,D 

A1ay.@QAEA 5zA~FF>3HNNPVqTUVWYXYZ 88E?D 4y:KZ ''Q/2: B Ws   C#C#C#C(C(
channel_idc                 >    t         | z  }|j                  dd       |S )z
    Get the output directory for a specific channel, creating it if needed.

    Returns:
        Path like: output/one_minute_history/
    T)parentsexist_ok)
OUTPUT_DIRmkdir)r   channel_dirs     r   get_channel_output_dirr   M   s'     z)KdT2    	timestampc                     |t        j                         }t        |       }|j                  d      }t	        |      }| d| d}||z  S )a^  
    Generate the output path for a video script.

    Args:
        channel_id: Channel identifier (e.g., "one_minute_history")
        premise: The video premise/title
        timestamp: Optional timestamp (defaults to now)

    Returns:
        Path like: output/one_minute_history/2025-02-15_14-25_tobacco-company-bought-womens-movement.json
    z%Y-%m-%d_%H-%M_.json)r   r9   r   strftimer   )r   r   r   r   time_strpremise_slugfilenames          r   get_video_output_pathr   Y   sY     LLN	(4K !!"23H09L1\N%0H!!r   opportunityc                    | j                  dd      }t        |||      }| j                  di       }|rt        |      nd}||t        j                         j                         | j                  dd      | j                  dd      | j                  d	i       j                  d
d      | j                  d	i       j                  dd      d||| j                  d      | j                  d      | j                  d      | j                  d      | j                  d      | j                  d      | j                  d      | j                  d      | j                  d      | j                  d
      | j                  d      | j                  d      | j                  d      d| j                  d      | j                  d	      d| j                  d      | j                  d      | j                  d      dd }t        |d!      5 }t        j                  ||d"t        #       d$d$d$       t        d%|j                  t                      |S # 1 sw Y   ,xY w)&a  
    Save a completed video generation result to the channel's output folder.

    The output file contains:
    - input: Original opportunity data (premise, research, etc.)
    - output: Script, evaluation, metadata
    - pipeline: Iteration history, timing, versions

    Args:
        opportunity: The completed opportunity dict with script and evaluation
        channel_id: Channel identifier
        timestamp: Optional timestamp for the filename

    Returns:
        Path to the saved file
    r   Untitledscript production_readyFiteration_countr   
evaluationverdictUNKNOWNcomposite_score)r   r   generated_atr   r   final_verdictfinal_scorefirst_frametrigger_mapopening_hookcore_revealdepth_checkemotional_payoff	structuretarget_audienceweighted_scoreresearch_word_countresearch_source_countresearch_report_content)r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r   r   director_metadataevaluator_metadataall_iterations)r   r   r   )metanarration_scriptinputr   pipeliner   r   indentdefaultNz    [Saved] )getr   extract_narration_scriptr   r9   	isoformatopenjsondumpstrprintrelative_tor   )	r   r   r   r   output_pathr   r   structured_outputfs	            r   save_video_outputr   r   s   * ooi4G'
GYGK __Xr*F;A/7r
 %$LLN446 +0BE J*/@!D(__\2>BB9iX&??<<@@ARTUV
 -&??=9&??=9'OON;&??=9&??=9 +0B C$5*/@A)oo.>?"y1#.??3H#I%0__5L%M'27P'Q
" "ooh/%//,7

 "-1D!E"-//2F"G)oo.>?
?$N 
k3	 ?1		#Qq#>? 
L00<=
>?? ?s   I

Ic                 T    t        |       }t        |j                  d      d      }|S )z
    List all video output files for a channel, sorted by timestamp (newest first).

    Returns:
        List of Path objects to JSON files
    z*.jsonTreverse)r   sortedglob)r   r   filess      r   list_channel_outputsr      s*     )4K;##H-t<ELr   r   c                 n   | j                  dg       }|syg }|D ]  }|j                  dg       }g }|D ]G  }|j                  dd      }|s|j                         s)|j                  |j                                I |sfdj                  |      }|j                  |        dj                  |      }	|	S )a  
    Extract all voiceover text from a script into a single narration string.

    Pulls voiceover from every segment in every beat, in order.
    Separates segments with blank lines, beats with --- dividers.
    Preserves all [beat], [pause], [thinking], [drops voice] markers.

    Args:
        script: The script dict containing beats with segments

    Returns:
        Single string ready for voice actor or TTS to read top to bottom
    beatsr   segments	voiceoverz

z

---

)r   stripappendr   )
r   r   
beat_textsbeatr   segment_textssegmentr   	beat_text	narrations
             r   r   r      s     JJw#EJ )88J+ 	8GK4IY__.$$Y__%67	8
 M2Ii() "":.Ir   c                 2    | rt         d|  dz  S t         dz  S )a  
    Get the path for opportunities JSON file.

    Args:
        channel_id: If specified, returns channel-specific path.
                   If None, returns the generic path (backward compatibility).

    Returns:
        Path to the opportunities JSON file
    analysis_opportunities_r   analysis_opportunities.json)r   )r   s    r   get_opportunities_pathr     s(     5j\GGG555r   c                     | rt        |       }|j                         r|S yd}t        t        j	                  |      d      }|r|d   S t        dz  }|j                         r|S y)a2  
    Find the latest analysis_opportunities file for the given channel.

    Args:
        channel_id: If specified, looks for channel-specific file.
                   If None, looks for any opportunities file (backward compatibility).

    Returns:
        Path to the latest opportunities JSON file
    Nzanalysis_opportunities_*.jsonTr   r   r  )r  existsr   r   r   )r   channel_filepatterntimestamped_files	base_files        r   get_latest_opportunities_filer    ss     -j9  .Gzw7F ## ::Ir   opportunities_datac                    t        |      }t        |d      5 }t        j                  | |dt               ddd       t        j                         j                  d      }|rt        d| d| dz  }nt        d| dz  }t        |d      5 }t        j                  | |dt               ddd       |S # 1 sw Y   xY w# 1 sw Y   |S xY w)	a  
    Save opportunities to channel-specific file (and optionally a timestamped backup).

    Args:
        opportunities_data: The full opportunities data dict
        channel_id: If specified, saves to channel-specific file.

    Returns:
        Path to the saved file
    r   r   r   Nz%Y%m%d_%H%M%Sr  r   r   )	r  r   r   r   r   r   r9   r   r   )r  r   r   r   r   timestamped_paths         r   save_opportunities_timestampedr  '  s     )4K 
k3	 @1		$a3?@ ''8I%*A*QykY^(__%*A)E(RR		$ @		$a3?@ @ @@ s   B5C5B>Cpromptmodeltimeoutc                 t   t        j                          }t        j                  ddd|ddg| dd|      }t        j                          |z
  }|j                  dk7  r(t	        d	|j                   d
|j
                  dd        |j                  j                         }d}t        j                  d|t        j                        }|r%	 t        j                  |j                  d            }|sKt        j                  d|t        j                        }	|	r$	 t        j                  |	j                               }|s]t        j                  d|t        j                  t        j*                  z        }|r%	 t        j                  |j                  d            }|st-        d|dd        ||fS # t        j                  $ r Y w xY w# t        j                  $ r}
t        |
d      r|
j                   nd}|	j                         }t#        d| d|
        t#        dt%        |       d       t        |
d      rY|
j                   rMt'        d|
j                   dz
        }t)        t%        |      |
j                   dz         }t#        d|||  d       Y d}
~
`d}
~
ww xY w# t        j                  $ r Y w xY w)ae  
    Call Claude CLI and parse JSON response.

    Args:
        prompt: The full prompt to send
        model: Model name ("opus" or "sonnet")
        timeout: Timeout in seconds

    Returns:
        Tuple of (parsed_json_dict, duration_seconds)

    Raises:
        RuntimeError: If Claude CLI fails
        ValueError: If response is not valid JSON
    claude--print--modelz-pr   T)r   capture_outputtextr  r   zClaude CLI failed (exit z): N   z```(?:json)?\s*(\{.*?\})\s*```r   z\{.*\}posunknownz)    [DEBUG] JSON parse error at position z: z    [DEBUG] JSON length: z chars2   z%    [DEBUG] Context around error: ......z^\s*(\{.*\})\s*$z,No JSON found in response. First 500 chars: i  )time
subprocessrun
returncodeRuntimeErrorstderrstdoutr   r   searchDOTALLr   loadsgroupJSONDecodeErrorhasattrr  r   r   maxmin	MULTILINE
ValueError)r  r  r  
start_timeresultdurationresponse_textparsedcode_block_match
json_matche	error_pos	json_textcontext_startcontext_endline_json_matchs                   r   call_clauder=  F  s     J^^	9ic:F yy{Z'HA5f6G6G5HFMMZ^[^L_K`abbMM'')M F yy!BMSUS\S\]	ZZ 0 6 6q 9:F
 YYy-C
mJ$4$4$67 ))$7		TVT`T`H`aO$9$9!$<= GVZWZH[G\]^^8A ## 		 '' 	m%,Q%6AEEI	&,,.	A)BqcRS1#i.1AHI1e$$'1552:$6M"%c)naeebj"AKA)MZeBfAggjkl	m" '' s=   $F. #G 3$J  .GGJB8JJ J76J7Z   target_durationrevision_instructionsc                 |   d}d}d}|rKt         rEt        |      }|r8|j                  }|j                  }|j                         j	                  dd      }| j	                  di       }t        |t              rt        j                  |d      }	nt        |      }	| j	                  dd      }
t        |
t              r#dj                  |
D cg c]  }d	| 	 c}      }n3t        |
t              rt        j                  |
d      }nt        |
      }| j	                  d
d      }t        |t              rt        j                  |d      }nt        |      }|t        v }|rt        |fi d|d|d|d| j	                  d| j	                  dd            d| j	                  dd      d|	d| j	                  dd      d| j	                  dd      d| j	                  dd      d| j	                  dd      d|d
|d| j	                  dd      d| j	                  dd      d|d| j	                  dd      d|}t        dd|      }nt        dd      }t        dd      }d}|rt!        d      }|j#                  |       }|j#                  ||xs d!||| j	                  d| j	                  dd            | j	                  dd      |	| j	                  dd      | j	                  dd      | j	                  dd      | j	                  dd      ||| j	                  dd      | j	                  dd      || j	                  dd      |"      }t%        |d#d$%      \  }}|d&|j	                  d'd#      d|||d(ut'        j(                  t*        j,                        j/                         t1        |d      d)d*S c c}w )+a  
    Layer 4 Director: Generate time-coded multi-track script from validated premise + research.

    Uses channel-specific prompts when available (v4 architecture).
    Each channel has its own voice, beat structure, pacing profile, and visual language.

    Args:
        opportunity: Opportunity dict with Layer 3 analysis + Layer 3.5 research
        channel_id: Channel ID for metadata lookup and prompt selection
        target_duration: Target video duration in seconds (60-120)
        revision_instructions: If provided, includes revision section in prompt

    Returns:
        Dict with script object and execution_metadata
    Generalr   competitive_gapr   r   r   r   
- r   channel_namechannel_descriptionr   suggested_titleUnknownr   r   r   r   r   r   r   r   r?  r   No research availabler@  layer4_directorv4)versionchannelrN  )r@  general)rG  r   rH  rC  r   r   r   r   r   r   r   r   r   r   r   r?  r   revision_sectionopusX  r  r  
4_directorr  N)layerr  prompt_versionchannel_specificrO  is_revisionr   duration_seconds)r   execution_metadata)r   r   descriptionto_dictr   
isinstancedictr   dumpsr   listr   r   r   r   r   r   formatr=  r   r9   r   utcr   round)r   r   r?  r@  rG  rH  rC  rO  r   trigger_map_strr   sstructure_strr   target_audience_struse_channel_specificr  metadataprompt_templaterR  revision_templateresponser2  s                          r   rL  rL    s   , LOkj)"<<L")"5"5%oo/334ErJO //-4K+t$**[;k*R0I)T"		Y"?Rs8"?@	It	$

9Q7I!oo&7<O/4("jjC!/2 &)CC -
%
 !4
 ,	

  OOI{?PR[/\]
 $r:
 (
 %<
 $r:
 $r:
 )__-?D
 $
 0
 '??+;Q?
  OOIr2
  ,!
" %0OO4MOf$g#
$ #8%
( ''8$PZ[ %%6E&'8$G   5d ;077Nc7d !''%!.Y 3+OOI{?PR[/\]#r:'$<#r:#r:(__-?D#/&??+;Q?OOIr2+$/OO4MOf$g-% ( 
, %V63GHh !\\'62" 4!0<$LL6@@B %h 2	
 W #@s   
N9c                 n   t        dd      }t        dd      }t        j                  | d      }|j	                  |      }d}d}||z   |z   }t        |d	d
      \  }}	d|j                  dd	      dt        j                  t        j                        j                         t        |	d      d|d<   |S )z
    Layer 4 Evaluator: Evaluate script against cognitive science criteria.

    Args:
        script: The script dict from layer4_director

    Returns:
        Dict with evaluation scores, verdict, and revision_instructions
    layer4_evaluatorrM  rP  r   rD  )script_jsona%  CRITICAL INSTRUCTION: You MUST respond with ONLY a valid JSON object.
- Do NOT include any text before the JSON
- Do NOT include any text after the JSON
- Do NOT wrap the JSON in markdown code blocks
- Start your response with the opening brace {
- End your response with the closing brace }

zc

REMINDER: Your response must be ONLY the JSON object. Start with { and end with }. No other text.rS  rT  rU  4_evaluatorr  rW  r  rX  r   r[  r\  )r   r   r   ra  rc  r=  r   r   r9   r   rd  r   re  )
r   rl  rk  rq  base_promptjson_enforcement_prefixjson_enforcement_suffixr  rn  r2  s
             r   rp  rp    s     !!3TBO"#5tDH **VA.K "(([(AKe %{25LLF %V63GHh gv. X\\2<<>!(A.&H!" Or   use_parallelc                    ddl m}m} t        j                         }| j	                  di       j	                  d|j	                  dd            }|j	                  dd      dd }| j	                  d	g       }t        d
 |D              }	d}
t        d|	 d       g }|D ]>  }|j	                  dg       D ]'  }|j                  |||j	                  dd      d       ) @ t        |      D ]  \  }}|d   }|d   }|d   j	                  dd      }|d   j	                  dg       j                  |      dz   }d| d| }|dkD  r||dz
     d   j	                  dd      nd}|t        |      dz
  k  r||dz      d   j	                  dd      nd} |||j	                  dd      |j	                  dd      ||j	                  dd      ||||	      }	 t        |d      }|rd|v r|j	                  dd      |d <   ||d!<   |j	                  d"d      |d#<   |j	                  dd$      }|d$k(  r?|j	                  d%i       }|j	                  d&|d          |d<   |j	                  d'      |d(<   nd|d)k(  r+|j	                  d*i       }|j	                  d&|d          |d<   n4|d+k(  r/|j	                  d,i       }d-|j	                  d.d/       |d<   ||d0<   |j	                  d1      r|d1   |d2<   |
dz  }
 t        j                         |z
  }t        d8|
 d9|	 d:|d;d<       |
|	t        |d=      dd>d?| d@<   | S # t        $ r:}t        d3| d4|        d$|j	                  dd      dd5 dd6d7|d!<   Y d}~d}~ww xY w)Aa  
    Layer 4 Visual Decider: Process each segment to determine optimal visual type.

    Takes a script from layer4_director and enhances each segment's visual field
    with structured visual specifications (IMAGE/VIDEO/DATA_VISUALIZATION).

    Args:
        script: The script dict from layer4_director
        opportunity: Full opportunity dict (for research access)
        use_parallel: Whether to process segments in parallel (faster but more API calls)

    Returns:
        Enhanced script with structured visual specifications
    r   )format_promptMETADATArk  r   r   r   Ni  r   c              3   R   K   | ]  }t        |j                  d g              ! yw)r   N)r   r   ).0r   s     r   	<genexpr>z(layer4_visual_decider.<locals>.<genexpr>n  s      I4TXXj"56Is   %'z!    [4-VisualDecider] Processing z segments...r   	beat_namerJ  )r   r   r~  r   r   beat_numberr   b_sr   
time_starttime_endr   )	
segment_idr  r  r~  r   previous_voiceovernext_voiceoverresearch_excerptr   sonnetr  decisionvisualvisual_originalvisual_structuredthinkingvisual_thinkingIMAGEimagesearch_queryera
visual_eraVIDEOvideoDATA_VISUALIZATIONdata_visualizationzDATA_VISUALIZATION: titleChartvisual_dataif_data_not_availablevisual_data_gapz         ! Segment z	 failed: r  )r  r  )r  r  u            → Processed /z segments in z.1frg  r   rM  )processed_segmentstotal_segmentsr[  r  rX  visual_decider_metadata)'prompts.prompt_v4.layer4_visual_deciderry  rz  r  r   sumr   r   	enumerateindexr   call_claude_json	Exceptionre  )r   r   rw  ry  rz  r0  r   r  r   r  	processedall_segmentsr   r   iitemr~  beat_numseg_idxr  prev_voiceoverr  r  r1  r  imgviddata_vizr7  r2  s                                 r   layer4_visual_deciderr  T  s   & PJjjR(,,Y	SU8VWG"'@"EetLJJw#EI5IINI	-n-=\
JK L xx
B/ 	G"!XXk9=! 	 \* @4y/%	 <##M15v,"":r288AAE
"WI.
 OPRSeac*9599+rJY[NORUVbRcdeReNeac*9599+rJkm !{{<3[[Q/kk+r2-)-

%	%fH=F*.-4[[2-F)* 06+,-3ZZ
B-G)* "::j':w& **Wb1C(+HY@Z([GH%,/GGENGL)( **Wb1C(+HY@Z([GH%!55%zz*>CH*>x||GU\?]>^(_GH%-5GM* ::56178O1PG-.Q	q@D yy{Z'H	#I;a/?}XVYNZ[
\] ((!(A.)F$% M)  	'
|9QC@A $*1++h*CCR*HQUV,G'(	s   DL33	M6</M11M6c           	      L   	 t        j                  dd| d|ddgddd      }|j                  d	k7  rt        d
|j                         |j
                  j                         }	 t        j                  |      }t        |t              r
d|v r|d   }n|}t        |      }t        j                  dd|      }t        j                  dd|      }t        j                  dd|      }|j                         }t        j                  d|      }|r#t        j                  |j!                               S t        j                  |      S # t        j                  $ r |}Y w xY w# t         j"                  $ r t        d      t        j                  $ r}t        d|       d}~ww xY w)zh
    Call Claude and parse JSON response.
    Uses the claude CLI for consistency with other calls.
    r  r  r  z--output-formatr   Tx   )r  r  r  r   zClaude CLI error: r1  z^```json\s*r   z^```\s*z\s*```$z\{[\s\S]*\}zClaude CLI timeoutzJSON parse error: N)r   r!  r"  r  r$  r%  r   r   r(  r_  r`  r*  r   r   r   r&  r)  TimeoutExpired)r  r  r1  r3  wrappercontentr6  r7  s           r   r  r    s   +2y&)U<MvV	
 !0@AA ++-	$jj/G'4(X-@!(+'
 g,&&W5&&R1&&R1--/ YY~w7
::j..011zz'""! ## 	$#G	$$ $$ .,-- 2,QC0112sC   A!E  $1E BE  0E  EE  EE   0F#FF#r   max_iterationsc           	         d}d}d}d}g }||k  r|dz  }t        d| d| d       	 t        | |||      }	|	d   }|	d	   }
|j                  d
i       }|j                  dt        |j                  dg                   }|j                  dd      }|j                  dd      }t        d| d| d| d       t        d       	 t        |      }|j                  d	i       }|j                  dd      }|j                  dd      }t        d| d|dd       |j                  ||||
|d!       |d"k(  rt        d#       nn||k  rS|j                  d$      }|r0|j                  d%g       }t        |      }t        d| d&| d'       nt        d| d(       nt        d| d)       ||k  r|r|d*   ni }|j                  d      }|r"t        d+       	 t        ||       }|r||d*   d<   || d<   |j                  d.      | d.<   |j                  d       | d <   |j                  d/      | d/<   || d0<   || d1<   |r|j                  d      d"k(  nd2| d3<   |rt        | |       | S # t        $ r(}t        d|        t        |      | d<   | cY d}~S d}~ww xY w# t        $ r2}t        d|        t        |      | d<   || d<   |
| d <   | cY d}~S d}~ww xY w# t        $ r}t        d,| d-       Y d}~d}~ww xY w)4u  
    Run the full v4 pipeline: Director → Evaluator → (Revise if needed) → Final

    Args:
        opportunity: Opportunity dict with Layer 3 analysis + Layer 3.5 research
        channel_id: Channel ID for metadata lookup
        target_duration: Target video duration in seconds (60-120)
        max_iterations: Maximum iterations (1 = no revision, 2 = one revision pass)

    Returns:
        Updated opportunity dict with:
        - script: The final script
        - evaluation: The final evaluation
        - director_metadata: Execution metadata from director
        - evaluator_metadata: Execution metadata from evaluator
        - iteration_count: Number of iterations used
        - production_ready: Boolean indicating if script passed evaluation
    r   Nr   z    [4-Director] Iteration r  r  )r   r   r?  r@  r   r\  rk  
beat_countr   
word_count?actual_duration            → z beats, 	 words, ~rg  z    [4-Director ERROR] layer4_director_errorz&    [4-Evaluator] Evaluating script...r   r   r   u            → Verdict: z	 (score: z.2f)z    [4-Evaluator ERROR] layer4_evaluator_errorr   )	iterationr   r   r   r   PRODUCTION_READYu2            → PRODUCTION READY - no revision neededr@  critical_failuresz - z critical failures, revising...z. - no revision instructions provided, stoppingz - max iterations reachedzE    [4-VisualDecider] Enhancing visuals with intelligent selection...z    [4-VisualDecider ERROR] z# - continuing with original visualsr   r   r   r   Fr   )
r   rL  r   r   r  r   rp  r   r  r   )r   r   r?  r  r  r@  r   r   r   director_resultr   r   r  r  r  r7  r   r   r   r  failure_countfinal_iterationfinal_scripts                          r   run_layer4_v4_pipeliner    s   0 I FJN
n
$Q	+I;a7GsKL	-'% /&;	O %X.F /0D E ::j"-D,FJJw4K0LMJ,4J"hh'8#>OM*Xj\?J[[\]^ 	68	)&1J!+0Db!I nnY	:G(nn->BO*7)9_S<QQRST 	"$!2"4
 	 ((FH ~%$.NN3J$K!$$.NN3F$K! #$5 6gYc-@_`agY.\]^M'*CDEM n
$R -;nR(O #&&x0LUW	Y0{KL/;r"8, )K / 3 3L AK'6':':;N'OK#$(7(;(;<P(QK$%%.K!"$2K !YcjnnY&?CU&UinK"# +z2[  	+A3/036q6K/0	  	,QC0147FK01$*K!/@K+,	^  	Y03VWXX	YsU   BI" AJ K "	J+JJJ	K'KKK	K7K22K7rX  c                 :   d}d}d}|rKt         rEt        |      }|r8|j                  }|j                  }|j                         j	                  dd      }t        d|      }t        d|      }|j                  |||| j	                  dd      | j	                  dd      | j	                  d	d      | j	                  d
i       j	                  dd      | j	                  dd      | j	                  dd      	      }	t        |	d      \  }
}|
j	                  dg       }|j                  d d       t        |      D ]  \  }}|dz   |d<    |d|j	                  dd      |t        j                  t        j                        j                         t!        |d      ddS )z
    Layer 4a: Generate 3-4 ranked video concepts from an opportunity.
    LEGACY - use v4 architecture for new implementations.
    rB  r   rC  layer4a_conceptrP  rI  rJ  the_questionmissing_angler   click_triggerr   r   r   rK  )	rG  rH  rC  rI  r  r  r  r   r   r  r  video_conceptsc                 &    | j                  dd      S )Nvirality_scorer   r   )xs    r   <lambda>z+layer4a_generate_concepts.<locals>.<lambda>  s    &6 : r   T)keyr   r   rank4ar  r   rs  )r  r\  )r   r   r]  r^  r   r   r   rc  r=  sortr  r   r9   r   rd  r   re  )r   r   rX  rG  rH  rC  rO  rl  rk  r  rn  r2  conceptsr  concepts                  r   layer4a_generate_conceptsr    s    LOkj)"<<L")"5"5%oo/334ErJO !!2NKO"#4nMH ##!/'#(99E __^R8!ooor:!oo&7<@@RTU"'7; +0IKb c $ 
F %V8<Hh ||,b1HMM:DMI  )  
7a%  #\\'84,$LL6@@B %h 2
	 	r   r  c                 J   d}d}d}|rKt         rEt        |      }|r8|j                  }|j                  }|j                         j	                  dd      }t        d|      }t        d|      }	|j	                  dg       }
t        |
t              rdj                  d |
D              }nt        |
      }|j                  ||||j	                  d	d      |j	                  d
d      |j	                  dd      |j	                  dd      ||j	                  dd      | j	                  dd      
      }t        |d      \  }}|j	                  di       }|d|	j	                  dd      |t        j                  t        j                         j#                         t%        |d      ddS )z
    Layer 4b: Generate a production-ready script from the #1 concept.
    LEGACY - use v4 architecture for new implementations.
    rB  r   rC  layer4b_scriptrP  data_pointsrE  c              3   &   K   | ]	  }d |   ywrF  N r|  dps     r   r}  z*layer4b_generate_script.<locals>.<genexpr>       #D"bI#D   r  hookcore_revelationemotional_arcshare_triggerr   rK  
rG  rH  rC  concept_titleconcept_hookconcept_core_revelationconcept_emotional_arcconcept_data_pointsconcept_share_triggerr   rS  r  video_script4br  r   rs  )r  r\  r   r   r]  r^  r   r   r   r_  rb  r   r   rc  r=  r   r9   r   rd  r   re  )r   r  r   rX  rG  rH  rC  rO  rl  rk  r  data_points_strr  rn  r2  r   s                   r   layer4b_generate_scriptr    s    LOkj)"<<L")"5"5%oo/334ErJO !!1>JO"#3^LH ++mR0K+t$))#D#DDk* ##!/'kk'2.[[, ',=r B%kk/2>+%kk/2> +0IKb c $ F %V6:Hh\\."-F \\'62,$LL6@@B %h 2
	 	r   c           	         t        d|      }t        d|      }|j                  |j                  dd      | j                  dd            }t	        |d	      \  }}|j                  d
i       }|d|j                  dd      |t        j                  t        j                        j                         t        |d      ddS )z
    Layer 4c: Generate shot-by-shot visual direction from script.
    LEGACY - use v4 architecture for new implementations.
    layer4c_visualrP  full_scriptr   r   rK  )r  r   rS  r  visual_direction4cr  r   rs  )r  r\  )r   r   rc  r   r=  r   r9   r   rd  r   re  )	r   r   rX  rl  rk  r  rn  r2  r  s	            r   layer4c_visual_directionr    s     !!1>JO"#3^LH ##JJ}b1 +0IKb c $ F %V6:Hh\\,b1F #\\'62,$LL6@@B %h 2
	 	r   c                 L   d}d}d}|rKt         rEt        |      }|r8|j                  }|j                  }|j                         j	                  dd      }t        d|      }t        d|      }	|j	                  dg       }
t        |
t              rdj                  d |
D              }nt        |
      }|j                  ||||j	                  d	d      |j	                  d
d      |j	                  dd      |j	                  dd      ||j	                  dd      | j	                  dd      
      }t        |dd      \  }}|j	                  di       }|d|	j	                  dd      |t        j                  t        j                         j#                         t%        |d      ddS )z
    Layer 4b (v3): Generate unified production spec - script + visual direction integrated.
    LEGACY - use v4 architecture for new implementations.
    rB  r   rC  layer4b_production_specrP  r  rE  c              3   &   K   | ]	  }d |   ywr  r  r  s     r   r}  z*layer4b_production_spec.<locals>.<genexpr>I  r  r  r  r  r  r  r  r   rK  r  rS  rT  rU  production_specr  r  r   rs  )r  r\  r  )r   r  r   rX  rG  rH  rC  rO  rl  rk  r  r  r  rn  r2  r  s                   r   r  r  ,  s    LOkj)"<<L")"5"5%oo/334ErJO !!:NSO"#<nUH ++mR0K+t$))#D#DDk* ##!/'kk'2.[[, ',=r B%kk/2>+%kk/2> +0IKb c $ F %V63GHhll#4b9O +\\'62,$LL6@@B %h 2
	 	r   r  c           	         t        d|      }t        d|      }|j                  di       j                  di       }t        j                  |d      }|j                  t        j                  |d      | j                  dd      |	      }t        |d
d      \  }}	|j                  di       }
|
d|j                  dd
      |t        j                  t        j                        j                         t        |	d      ddS )z
    Layer 4c (v3): Generate detailed asset specs for graphics, infographics, images.
    LEGACY - use v4 architecture for new implementations.
    layer4c_asset_specsrP  rk  color_paletter   rD  r   rK  )r  r   r  rS  rT  rU  asset_specsr  r  rs  )r  r\  )r   r   r   r   ra  rc  r=  r   r9   r   rd  r   re  )r   r  rX  rl  rk  r  color_palette_strr  rn  r2  r  s              r   r  r  l  s     !!6OO"#8.QH $''
B7;;ORPM

=; ##

?1= +0IKb c' $ F %V63GHh,,}b1K #\\'62,$LL6@@B %h 2
	 	r   c           	      N   g d}|D ]  }| j                  |d        t        d       	 t        | ||      }|d   | d<   |d   | d<   t        |d         }|dkD  r|d   d   j	                  dd	      nd	}t        d
| d|        | j	                  dg       }	|	sd| d<   | S |	d   }
|j                  d      }|rt        d       	 t        | |
||      }|d   | d<   |d   | d<   |d   }|j	                  di       }|j	                  dt        |j	                  dg                   }|j	                  dd	      }t        d
| d| d       | j	                  di       }t        d       	 t        | ||      }|d   | d<   |d   | d<   |d   }|j	                  dd	      }t        d
| d       | S t        d"       	 t        | |
||      }|d#   | d#<   |d   | d<   |d#   j	                  d$d	      }|d#   j	                  d%d	      }t        d
| d&| d'       | j	                  d#i       }t        d(       	 t        | ||      }|d)   | d)<   |d   | d<   t        |d)   j	                  dg             }|d)   j	                  d*i       }|j	                  d+d	      }t        d
| d,| d-       | S # t
        $ r(}t        d|        t        |      | d<   | cY d}~S d}~ww xY w# t
        $ r(}t        d|        t        |      | d<   | cY d}~S d}~ww xY w# t
        $ r'}t        d |        t        |      | d!<   Y d}~| S d}~ww xY w# t
        $ r(}t        d|        t        |      | d<   | cY d}~S d}~ww xY w# t
        $ r'}t        d |        t        |      | d!<   Y d}~| S d}~ww xY w).u   
    Run the legacy 4a → 4b → 4c chain for a single opportunity.
    LEGACY - use v4 architecture for new implementations.
    )r  layer4a_metadatalayer4a_errorr  r  layer4b_metadatalayer4b_errorr  r  layer4c_metadatalayer4c_errorNz(    [4a] Generating concepts (Sonnet)...r  r\  r  r   r  r  r  z) concepts generated, top virality score: z    [4a ERROR] r	  zNo concepts generated by 4ar  v3z-    [4b] Generating production spec (Opus)...r  r
  rk  
shot_countshotstotal_runtime_secondsz	 shots, ~z	s runtimez    [4b ERROR] z)    [4c] Generating asset specs (Opus)...r  r  total_assets_neededz assets specifiedz    [4c ERROR] r  z$    [4b] Generating script (Opus)...r  r  estimated_duration_secondsr  z
s durationz.    [4c] Generating visual direction (Opus)...r  summaryinfographics_neededz shots, z infographics needed)popr   r  r   r   r  r   
startswithr  r  r  r  )r   r   rX  fields_to_clearfield	result_4anum_concepts	top_scorer7  r  top_conceptuse_v3_architecture	result_4bspecr   r  runtimer  	result_4cassetstotal_assetsr  r2  r   	num_shotsr  infographicss                              r   !run_video_generation_chain_legacyr'    st   O
 ! %t$% 

45-k:~V	(12B(C$%*34H*I&'9%567Q]`aQaI./2667GMgj	l^+TU^T_`a /4H'DO$1+K )33D9=>	/[*VdeI-67H-IK)*.78L.MK*+./D88J+D,DHHWb4I0JKJhh6<GM*YwiyIJ &//*;R@ 	9:	2+K.YI)2=)AK&.78L.MK*+}-F!::&;SALM,/@ABR C 	45	/[*VdeI*3N*CK'.78L.MK*+">266|SIJ 0445QSVWHM*Yxj
KL 4 	>?	20fnUI.78J.KK*+.78L.MK*+I&89==grJKI 2377	2FG";;'<cBLM)H\NBVWX o  s#$'*1vO$<  	OA3'(+.q6K(	$  	2OA3'(+.q6K(J O	2   	OA3'(+.q6K(	&  	2OA3'(+.q6K(		2s   AJ% BK &AL 7AM  /A4M4 %	K.KKK	L
"L?L
L
	L=L88L= 	M1	M,&M1,M14	N$=NN$rM  c                 ^    |j                  d      rt        | ||d      S t        | ||      S )ua  
    Run the video generation chain for a single opportunity.

    Automatically selects the appropriate architecture based on prompt_version:
    - v4: Director → Evaluator → (Revise if needed)
    - v1/v2/v3: Legacy 4a → 4b → 4c chain

    Args:
        opportunity: Must have research_completed=True (or use skip_research)
        channel_id: Channel for metadata lookup
        prompt_version: Prompt version to use ("v4" for new architecture)
        target_duration: Target video duration in seconds (for v4)

    Returns:
        Updated opportunity dict with video generation fields added
    rM  r   )r   r   r?  r  )r   r   rX  )r  r  r'  r   r   rX  r?  s       r   run_video_generation_chainr*    sC    ,   &%#!+	
 	
 1#!)
 	
r   specific_idskip_researchc                    t        d       t        d| d       t        d       |j                  d      rt        d       nt        d       | j                  dg       |<|d
k  s|t              k\  r t        d| dt              dz
   d       | S ||   fg}n3t	              D cg c]  \  }}|j                  dd      s|r||f }}}|st        d       t        d       | S t        dt        |       d       t        d|        t        d| d       |rt        d|        | j                  d      }	|D ]9  \  }
}|j                  d|j                  dd            d	d }t        d|
 d| d       t        ||||       }||
<   |	sU|j                  d!      g|j                  d      r&d"|v xr |d"   d	u}|j                  d#d      }|rd$nd%}nd&|v xs d'|v }d(|v }|r|sd$nd%}	 |j                  d      r3t        |	|d!   |d	|j                  d"      |j                  d)      *       nAt        |	|d!   ||j                  d+      |j                  d&      |j                  d,      *       < | d<   t        j                  t        j                        j                         | d.<   || d/<   t        d0       t        d1       t        d2       |j                  d      rnt        fd3|D              }t        fd4|D              }t        d5t        |              t        d6|        t        d7|        t        d8||z
          | S d9 t        fd:|D              }t        d5t        |              t        d;|        t        d<t        |      |z
          | S c c}}w # t        $ r}t        d-|        Y d	}~d	}~ww xY w)=a  
    Run video generation chain for opportunities.

    Args:
        opportunities_data: Full opportunities JSON data
        channel_id: Channel ID for context
        specific_id: If set, only process this opportunity index
        prompt_version: Prompt version to use ("v4" recommended)
        skip_research: If True, process even without research
        target_duration: Target video duration in seconds

    Returns:
        Updated opportunities_data with video fields added
    z=
============================================================zLAYER 4: VIDEO GENERATION (vr  z<============================================================rM  u;   Architecture: Director → Evaluator → (Revise if needed)u%   Architecture: Legacy 4a → 4b → 4copportunitiesNr   z [ERROR] Invalid opportunity ID: z (valid: 0-r   research_completedFz5[WARN] No opportunities eligible for video generationz<       (Need research_completed=true or use --skip-research)z[4.0] Processing z opportunity(ies)z      Prompt version: z      Target duration: rg  z      Channel: analysis_run_idrI  r   rJ  r  z
[z] r  r)  
cluster_idr   r   	completedfailedr  r  r  r   )r0  r1  video_gen_statusr  r  r  r  r  z+    [WARN] DB update for video gen failed: video_generation_timestampvideo_generation_versionz=
------------------------------------------------------------zVIDEO GENERATION SUMMARYz<------------------------------------------------------------c              3   P   K   | ]  \  }}|   j                  d       d  yw)r   Nr   r  r|  r  r   r.  s      r   r}  z9run_video_generation_for_opportunities.<locals>.<genexpr>  s3      
!QQ##H-9 
s   #&c              3   R   K   | ]  \  }}|   j                  d d      rd   yw)r   Fr   Nr  r8  s      r   r}  z9run_video_generation_for_opportunities.<locals>.<genexpr>  s3      %
!QQ##$6> %
s   $'z  Processed: z  Scripts generated: z  Production ready: z  Need revision: c                 ,    d| v xs d| v }d| v }|xr | S )Nr  r  r  r  )opp
has_output	has_errors      r   is_successfulz=run_video_generation_for_opportunities.<locals>.is_successful  s-    *c1J^s5JJ'3.I/i-/r   c              3   @   K   | ]  \  }} |         sd   yw)r   Nr  )r|  r  r   r>  r.  s      r   r}  z9run_video_generation_for_opportunities.<locals>.<genexpr>  s"     X$!QmTUFV8WAXs   z  Successful: z
  Failed: )r   r  r   r   r  r*  r   r  r   r9   r   rd  r   r  )r  r   r+  rX  r,  r?  
to_processr  r;  r0  idxr  updated_oppr<  is_production_readyvideo_statusr=  r7  success_countproduction_ready_countr>  r.  s                       @@r   &run_video_generation_for_opportunitiesrG  7  s[   , 
/	((8
:;	(O  &KL56&**?B?M ?kS-??4[MSQ^M_`aMaLbbcde%%"M+$>?@
 $-]#;
Cww+U3} H

 

 EFLM!!	c*o..?
@A	">"2
34	#O#4A
67
|,- ),,->?O .IS)3779i+HI#2NC55'%& 1!)+	
 )c {|<H((.%4ZX9NVZ9Z
&1oo6H%&P#.8{h.+=^S^A^
+{:	/9){RZI!,,T2;(7#.|#<)5'+(3(A$/OOL$A <(7#.|#<)5'27G'H(38I(J$/OOM$BK.Ib +8'7?||HLL7Q7[7[7]345C12 
/	
$%	(O   & 
$
 
 "% %
$%
 "
 	c*o./0%m_56$%;$<=>!-2H"H!IJK 	0
 X*XXc*o./0}o./
3z?]:;<=M
@  ICA3GHHIs   ."N9:BN??	O!OO!__main__r  zNo opportunities file found at r   r)r+  rX  r?  r   rD  z

Saved to )r  )N)rS  i,  )Nr>  N)F)r  )Nr>  r   )Nv1)rJ  )Nr  )r  )NrM  r>  )NNrM  Fr>  )D__doc__r   r   r   r  r   r   pathlibr   typingr   r   r   r	   r
   promptsr   r   r   r   r   db_opportunitiesr   channel_configr   ImportError__file__parentr   r   intr   r   r   r   r   r   r  r  r  floatr=  rL  rp  boolr  r  r  r  r  r  r  r  r'  r*  rG  __name__sysr   r  r   exitr   r   loaddatar1  r   r  r   r   <module>r\     sT  
  	   '  3 3 D  D E*
 (^""X-
"3 "C " "J	s 	t 	"c "C "H "X\ "8 Ic3hII I 
	IX	S 	T$Z 	%T#s(^ % %X6s 6d 6 c T BtCH~ SV bf >I IC I3 ItTWY\T\~_dOdIe Id !%	Bc3hBB B 	B
 
#s(^BJ2cN2	#s(^2x xcNxc3hx x 
#s(^	xv12S 12 12DcN 12l 	Ac3hAA A 	A
 
#s(^AT :c3h:: : 
#s(^	:@ 	=c3h=#s(^= = 	=
 
#s(^=F !c3h!cN! ! 
#s(^	!N 	=c3h=#s(^= = 	=
 
#s(^=F &c3h&#s(^& & 
#s(^	&V tc3htt t 
#s(^	tz 	$
c3h$
$
 $
 	$

 
#s(^$
R PS#XPP P 	P
 P P 
#s(^Pf zx.''(25RRK/}=>	k3	 1tyy| 4	F 
k3	 '1		&!A&' 
K}
%&3 [-  Kn- ' 's*   K6 LL6L LLL