
    Pj2.                        d Z ddlZddlZddlZddlZddlZddlZddlZddl	m	Z	m
Z
 ej                  j                  ej                  j                  e            ZdZdZdZdZdZd	Zd
dddZd Zd ZddZddZd Zedk(  r e        yy)ud  Build one ~20-minute themed episode script from a collect_day.py material file.

Segments: cold open -> radar briefing -> day anchor (-> Friday zeitgeist) -> outro.
Each segment is written by the chosen writer with its own word budget, then
concatenated into one script file + .meta.json in the exact format
tts_vibevoice.py already renders.

Writers:
  local  — gemma on :8000 (the production default)
  claude — `claude -p` (claude-sonnet-5), no tools; same prompts, same material

Usage: build_episode.py --day thu|fri|sat --writer local|claude            --material material.json --script-out script.txt
    N)datetimetimezonez)http://localhost:8000/v1/chat/completionszgemma4-26b-a4bzclaude-sonnet-5u  SPEECH-SAFETY RULES (this text goes directly to a text-to-speech engine):
- Plain spoken prose ONLY. No markdown, no asterisks, no headers, no bullet lists.
- Never write citation brackets like [1]; name authors naturally or say "one earlier study".
- Never write URLs, arXiv IDs, file paths, or version strings.
- No mathematical notation or symbols: say "F one score" not "F1", "about eighty-seven
  percent" not "87%". Expand acronyms on first use. Numbers under twenty as words.
- Never attempt to pronounce Lakota or other Indigenous-language words; describe them
  ("the Lakota word for plums") or spell them letter by letter, naming diacritics.
  Machine pronunciation of these words teaches learners errors.
This is ONE SEGMENT of a continuous episode: no greeting, no sign-off, no
"welcome back" — open with at most a one-sentence transition, unless the segment
instructions say otherwise.
- Never narrate the show's structure or your own process: no meta commentary
  about the script, the sources, or what you are about to do; no filler
  signposts like "let's dive in" or "that wraps up this segment". Transition
  through content, not announcements.zThe listener builds community-sovereign language AI for Lakota (OCR of
legacy texts, RAG grounded in community-approved books, per-stage evaluation,
community-governed data) and listens while driving.u  This episode has TWO hosts in conversation:
- Speaker 1 leads: frames each topic, carries the narrative, addresses Mason directly.
- Speaker 2 is the analyst: asks the questions a sharp listener would ask, adds
  caveats and context, pushes back when a claim is thin.
FORMAT: every turn is ONE line starting with exactly "Speaker 1:" or "Speaker 2:"
followed by that host's words. Never put a speaker tag mid-line. No names, no
stage directions, no other formatting.
Make it a real conversation — reactions, short interjections, genuine questions,
occasional disagreement — never two alternating monologues. Turns should vary in
length; most under sixty words.)u3   Roundup — Native language tech & data sovereigntyz0weekly Native research and language-tech roundup)zGeoAI deep-dive + AI zeitgeistz5a geospatial AI deep-dive plus the week in general AI)zWeek in reviewz0synthesis of everything the radar kept this weekthufrisatc                    t         dt        |dz        dz   d| dgd}t        j                  j	                  t
        t        j                  |      j                         ddi	      }t        j                  j                  |d
      5 }t        j                  |      d   d   d   d   j                         cd d d        S # 1 sw Y   y xY w)Ng333333?g@,  user)rolecontent)modeltemperature
max_tokensmessageszContent-Typezapplication/json)dataheadersX  )timeoutchoicesr   messager   )LLMinturllibrequestRequestLLM_URLjsondumpsencodeurlopenloadstrip)promptbudget_wordsbodyreqrs        podcast/build_episode.pywrite_localr*   ?   s    Cs@R<SVY<Y"(V<=?D
..
 
 tzz$/?/F/F/H*8:L)M ! OC			S		1 HQyy|I&q))4Y?EEGH H Hs   	/CCc                    | dz  } t        j                  dddt        ddg| dddd	
      }|j                  dk7  rt	        d|j
                  d d        t        j                  d|j                  t        j                        }|st	        d|j                  d d        |j                  d      j                         S )Nz

Write the segment between two marker lines: a line containing exactly <<<SCRIPT>>> before it and a line containing exactly <<<END>>> after it. Nothing but spoken prose between the markers.claudez-pz--modelz--disallowedToolszARead,Write,Edit,Bash,Glob,Grep,WebSearch,WebFetch,Agent,TodoWriteTi  z/tmp)inputcapture_outputtextr   cwdr   zclaude -p failed:   z <<<SCRIPT>>>\s*(.*?)\s*<<<END>>>z"claude -p output missing markers: r
      )
subprocessrunCLAUDE_MODEL
returncodeRuntimeErrorstderrresearchstdoutSgroupr#   )r$   r%   r(   ms       r)   write_clauder?   H   s      S TF 		4L2E	L	NTcv	OA 	||q/#/?@AA
		5qxxFA?#?OPQQ771:    c                    g }| D ]i  }|j                  d      xs |j                  dd      }|j                  d|d    ddj                  |j                  dg             d d	  d
|d d         k dj                  |      d |dz   S )Nwhysummary z- titlez (z, authorsd   z): r1   

   )getappendjoin)itemscapoutitrB   s        r)   items_blockrQ   Z   s    
C _ffUm4rvvi4

R7}Btyy	21F'G'M&NcRUVZWZR[Q\]^_ 99S>)38$$r@   c                 l   | d   | d   }}t         |   \  }}t        }|dk(  r|dt        z   dz   z  }g }dddd	}|j                  d
d| dt         d| d||    df       |j                  dd| dt         dt        | d         xs d f       |dk(  r<|j                  dd| dt         dt        j                  | d   d      dd  f       n|dk(  ro| d   }	|j                  dd| d|	d    d!    d"|	d#    d$|	d%   dd&  f       |j                  d'd(| dt         d)t        j                  | d'   d      dd*  f       nY|d+k(  rT|j                  d,d| dt         d-t        | d.   d/0       d1t        j                  | j                  d2g              f       | j                  dg       D 
cg c]  }
|
d!   	 c}
d| v r| d   d    d!   gng | j                  d.g       dd3 D cg c]  }|d!   	 c}d	|   }|j                  d4d5| d6| d7d8j                  |      dd9  f       |S c c}
w c c}w ):z<Return [(name, budget_words, prompt), ...] in episode order.daydate   

zH
When a segment says to start with a specific phrase, Speaker 1 says it.z'the weekly Native language-tech roundupz6a geospatial AI deep-dive, then the week in general AIzthe week in reviewr   	cold_openx   z

Write the COLD OPEN of today's episode, about 120 words. Exception to the
transition rule: start with exactly "Hey Mason!" then the date in natural
speech (z^), then preview what's coming: a quick radar briefing over the
newest kept research, and then zC. Energetic but not cheesy.
End by leading into the radar briefing.radari&  a  

Write the RADAR BRIEFING segment, about 550 words. These are the items the
research filter kept in the last few days. Group them by theme rather than
reading a list; for each item or theme, one or two sentences on what it is and
why it matters to the listener's work. If items are weak or repetitive,
prioritize ruthlessly and say less. If there are no items below, say the radar
was quiet and move on in two sentences.

ITEMS:
z(none)r   roundupil  u"  

Write the main segment, about 1900 words: the WEEKLY ROUNDUP of Native and
Indigenous language technology and data-sovereignty news. For each story: what
happened, who is doing it, and why it matters through a community-sovereignty
lens — what it says about who controls language data, what peer nations'
approaches suggest for Lakota work. These are news reports, not papers: be
honest about what is announced versus demonstrated. Prioritize; drop weak items
rather than padding. Weave stories into a narrative where they connect.

STORIES:
newsr2   )indentNi6  r   geoaiiF  aB  

The listener is also a geospatial practitioner: he builds visualizations and
tools with Sentinel-2 and other satellite imagery, and runs local models on his
own hardware.

Write the main segment, about 1350 words: a DEEP-DIVE on one geospatial AI
paper. Cover: the problem and why it exists; how the method works mechanically;
the handful of findings that matter, each with a sentence of context; honest
limitations; and close with what the listener should actually try with his own
imagery work, and what to ignore. Never recite more than two numbers in a row.

PAPER TITLE: paperrE   z
WHY PICKED: reasonz
PAPER TEXT (truncated):
r/   i0u  	zeitgeisti  a  

Write the AI ZEITGEIST segment, about 650 words: the week in general AI, for
someone who runs local models and builds language AI but skips the hype cycle.
Open with a one-sentence transition from the paper deep-dive that came before.
Pick only the developments that actually matter and frame each one: what does
this mean for local inference, small models, evaluation, or data governance.
Skepticism welcome where earned.

DEVELOPMENTS:
i'  r   reviewum  

Write the main segment, about 1900 words: the WEEK IN REVIEW. Synthesize
everything the research radar kept this week — this is the one segment that
connects things instead of reporting them. What themes emerged across papers?
Which items relate to or contradict each other? What actually moved this week
in the listener's areas (low-resource NLP, RAG evaluation, OCR, data
sovereignty), and what should he carry into next week? Refer back to episodes
already covered this week (listed below) briefly rather than re-explaining
them. If the week was thin, say so and go deeper on fewer items.

THIS WEEK'S KEPT ITEMS:
weeki@  )rN   z&

EPISODES ALREADY COVERED THIS WEEK:
episodes_this_week   outroP   z

Write the OUTRO, about 80 words. Exception to the transition rule: this closes
the episode. One or two sentences wrapping up today (u   ), a light sign-off
addressed to Mason. No URLs, no "subscribe" boilerplate. You have all the
context you need — never ask for more. Today's episode covered a radar briefing
plus: z; r   )
DAY_METASPEECH_RULESDIALOGUE_RULESrK   LISTENERrQ   r   r   rJ   rL   )matspeakersrS   rT   rE   blurbrulessegsanchor_namesgnwcovereds                r)   segments_forru   b   s,   E
CKCC=LE5E1}&>)]^ 	_DDS/1L 	KKcw /	
 	 
   ,S 12 3($+ , - 	KK#E7 +	
 
 S\&h ' + , - e|Y5' 2	
  CK"6E* +'/ 0 	1 
LWd 0 j!" #x[M 66E %  	  	[#E7 3	
 
 CQ'/ 0(4 5 	6 
Xt% 1	
  S[d# $ % CGG("-. /#&3 4 	5& ,/7762+>?aqz?:AS.s7|G,W56b+.7762+>r+BCaqzCEEHJG 	KK"5' *6 7<W = yy$3 $ % & K @Cs   2H,(H1c                     t        j                         } | j                  ddg d       | j                  ddddg       | j                  dd	       | j                  d
d	       | j                  dt        dddg       | j	                         }t        j                  t        |j                              }|d   |j                  k(  sJ d|d    d|j                          |j                  dk(  rt        nt        }g }t        ||j                        D ]Z  \  }}}t        d|j                   d|j                   d| d| d	t         j"                         |j%                   |||             \ dj'                  |      }|j                  dk(  rt)        j*                  dd|      }t,        |j                     \  }	}
|j                  |j                  dk(  rdndz   }|j                  dk(  rdnd}t/        j0                  t2        j4                        j7                  d      }t        |j8                  d      j;                  |       t        j<                  |	 d |d!    d"| d#d$| d%|
 | d&|j                   d&|j                   | d'|j                  d(t        |j8                  d)z   d             t        d|j                   d|j                   d*t?        |jA                                d+|j8                          y ),Nz--dayTr   )requiredr   z--writerlocalr,   z
--material)rw   z--script-outz
--speakersr2   rU   )typedefaultr   rS   zmaterial file is for z, not z
[episode] /z
: writing z (~zw)...)filerV   z!(?<=\S)[ \t]+(Speaker\s*[12]\s*:)z\n\1z
, 2 voicesrD   _2vz%Y%m%d_%H%Mrs   u    — rT   z [](z	 writer) _z.mp3)rE   descriptionmp3rl   z
.meta.jsonz: z
 words -> )!argparseArgumentParseradd_argumentr   
parse_argsr   r"   openmaterialrS   writerr*   r?   ru   rl   printsysr8   rK   rL   r9   subrg   r   nowr   utcstrftime
script_outwritedumplensplit)apargsrk   r   partsnamebudgetr$   scriptrE   rm   labelsuffixstamps                 r)   mainr      s   		 	 	"BOOGd4IOJOOJ7JOKOOL4O0OONTO2OOLsA1vOF==?D
))D'
(Cu:!W%:3u:,fTXXJ#WW!;;'1K|EE ,S$-- @ ,ff
488*Adkk]*TF#fXUS::	U66*+, [[F}}<gvNDHH%LE5KK4==A+=<2FEmmq(UbFLL&//>E#$$V,II5's6{m2eWA> !%	%9q
!DKK=E==* 4??\137	9
 
Jtxxj$++bV\\^1D0E F " #r@   __main__)i	  )r2   )__doc__r   r   osr9   r3   r   urllib.requestr   r   r   pathdirnameabspath__file__HEREr   r   r5   rh   rj   ri   rg   r*   r?   rQ   ru   r   __name__ r@   r)   <module>r      s    ? > > > '	wwrwwx01
5 )"7	# wfQH$%sl"#J zF r@   