Keep LLM review advisory, add backup queries, faster image size, catch echoed vision replies

This commit is contained in:
Justin Oros
2026-09-20 18:40:12 -07:00
parent 29fc72df71
commit 71730bc6a7
2 changed files with 38 additions and 21 deletions
+33 -17
View File
@@ -66,8 +66,8 @@ GLOBAL_DEFAULTS = {
"sd_model": "stabilityai/sdxl-turbo",
"sd_steps": 4,
"sd_guidance": 2,
"sd_width": 768,
"sd_height": 1344,
"sd_width": 704,
"sd_height": 1216,
"tts_engine": "auto",
"tts_voice": "af_heart",
"tts_rate": 170,
@@ -91,6 +91,7 @@ PROFILE_DEFAULTS = {
"upload_category_id": "24",
"privacy_status": "private",
"trending_query": "",
"trending_queries": "",
"trending_days": 7,
"category_id": "",
"region_code": "US",
@@ -644,12 +645,19 @@ def filter_language(videos, lang, strict=False):
return kept
def fetch_trending(s):
def profile_queries(s):
extra = [q.strip() for q in re.split(r"[,\n]", s.get("trending_queries", "")) if q.strip()]
main = s["trending_query"].strip()
queries = ([main] if main else []) + extra
return queries
def fetch_trending(s, query=None):
yt = youtube_client(s["profile_id"])
count = max(1, min(int(s["trending_count"]), 50))
region = s["region_code"] or "US"
lang = s["source_language"].strip().lower()
query = s["trending_query"].strip()
query = (query if query is not None else s["trending_query"]).strip()
if query:
after = (datetime.now(timezone.utc) - timedelta(days=max(1, int(s["trending_days"])))).strftime("%Y-%m-%dT%H:%M:%SZ")
params = {
@@ -991,10 +999,7 @@ Return {{"violations": []}} if no rule is broken."""
def review_mode(s):
mode = s["kids_llm_review"] if s["kids_llm_review"] in REVIEW_MODES else "advisory"
if mode == "advisory" and not s["kids_manual_review"]:
return "block"
return mode
return s["kids_llm_review"] if s["kids_llm_review"] in REVIEW_MODES else "advisory"
def produce_script(s, src):
@@ -1002,8 +1007,6 @@ def produce_script(s, src):
feedback = []
attempts = 4 if kids else 1
mode = review_mode(s)
if kids and mode != s["kids_llm_review"]:
logger.info("LLM review switched to block mode because manual review is off")
for attempt in range(1, attempts + 1):
check()
set_stage("writing script")
@@ -1081,8 +1084,12 @@ def kids_vision_check(s, clip_path):
try:
try:
data = ollama_call(s, KIDS_VISION_PROMPT, temperature=0.1, model=model, images=images, num_predict=256)
safe = truthy(data.get("safe"))
desc = str(data.get("description", ""))
reason = str(data.get("reason", ""))
echoed = "it is unsafe if" in reason.lower() or reason.strip().lower() in ("why", "short explanation")
if echoed or desc.strip().lower() in ("what you see", "description"):
raise ValueError("model echoed the prompt")
safe = truthy(data.get("safe"))
except (requests.exceptions.HTTPError, ValueError):
text = ollama_call(s, VISION_TEXT_PROMPT, temperature=0.1, model=model, images=images, num_predict=128, as_json=False)
low = text.lower()
@@ -1371,14 +1378,23 @@ def run_job(s):
", manual review hold" if s["kids_manual_review"] else "",
)
set_stage("fetching trending videos")
trending = fetch_trending(s)
state = load_state()
candidates = [v for v in sorted(trending, key=lambda v: -v["views"]) if v["id"] not in state["processed"]]
queries = profile_queries(s) or [""]
candidates = []
for q in queries:
check()
trending = fetch_trending(s, q)
found = [v for v in sorted(trending, key=lambda v: -v["views"]) if v["id"] not in state["processed"]]
if kids:
safe = [v for v in candidates if not KIDS_BANNED.search(v["title"])]
if len(safe) < len(candidates):
logger.info("Skipped %d source videos with themes unsuitable for kids", len(candidates) - len(safe))
candidates = safe
safe = [v for v in found if not KIDS_BANNED.search(v["title"])]
if len(safe) < len(found):
logger.info("Skipped %d source videos with themes unsuitable for kids", len(found) - len(safe))
found = safe
if found:
candidates = found
break
if len(queries) > 1:
logger.info("Nothing new for '%s', trying the next query", q or "trending chart")
if not candidates:
logger.warning("No usable trending videos, checking again in 30 minutes")
set_stage("waiting for new trending videos")
+4 -3
View File
@@ -117,11 +117,12 @@ const FIELDS=[
["channel_niche","Channel niche","wide","Steers every script, e.g. 60 second animated movies for kids ages 3 to 7","p"],
["made_for_kids","Made for kids","checkbox","Flags uploads as made for kids and enforces child-safe rules, word filters, LLM compliance review, and frame vision checks","p"],
["kids_manual_review","Hold kids videos for manual review","checkbox","Forces made-for-kids uploads to private so you can watch them before publishing","p"],
["kids_llm_review","LLM script review","select:advisory=Advisory (show notes, you review)|block=Block (reject flagged scripts)|off=Off","Advisory only applies while manual review is on, otherwise it blocks. Word filters and vision checks always block","p"],
["kids_llm_review","LLM script review","select:advisory=Advisory (show notes, you review)|block=Block (reject flagged scripts)|off=Off","Advisory logs notes without blocking. Word filters and vision checks always block","p"],
["upload_category_id","Upload category","select:"+CATS,"","p"],
["privacy_status","Upload privacy","select:private|unlisted|public","","p"],
["ai_disclosure","Disclose AI generated content","checkbox","YouTube only requires this for realistic synthetic content, not cartoons. Leave on to be transparent with parents","p"],
["trending_query","Trending search query","text","Blank uses the general trending chart. e.g. kids animated story","p"],
["trending_queries","Backup search queries","wide","Comma separated. Tried in order when the main query has nothing new left","p"],
["trending_days","Search window (days)","number","Only used with a search query","p"],
["category_id","Source category","select:=All|"+CATS,"Filters source videos","p"],
["region_code","Region","text","Two-letter country code, e.g. US","p"],
@@ -141,8 +142,8 @@ const FIELDS=[
["sd_model","Image model","text","Hugging Face model id, e.g. stabilityai/sdxl-turbo or stabilityai/stable-diffusion-xl-base-1.0","g"],
["sd_steps","Image steps","number","4 for turbo models, 20 to 30 for standard models","g"],
["sd_guidance","Image guidance","number","2 for turbo models, 7 for standard models. Below 1.1 the anatomy filter stops working","g"],
["sd_width","Image width","number","768 avoids duplicated subjects. Larger is slower","g"],
["sd_height","Image height","number","1344 is the correct vertical ratio for SDXL","g"],
["sd_width","Image width","number","704 is a good speed and quality balance. Larger is much slower","g"],
["sd_height","Image height","number","1216 keeps the vertical ratio SDXL expects","g"],
["tts_engine","Narration engine","select:auto=Auto (best available)|kokoro=Kokoro (most natural)|piper=Piper|say=macOS say|espeak=espeak-ng","Missing engines are installed automatically on the next run","g"],
["tts_voice","Narration voice","text","Kokoro: af_heart, af_bella, af_nicole, am_michael, bf_emma. Ignored by the system voice","g"],
["tts_rate","Narration speed","number","Only used by the system voice. Words per minute","g"],