"""台本の読み物(台本_*.md)と codex 敵対的検証の依頼(codex_*.md)を、narration.py から作り直す。 台本を直したら、動画の作業フォルダで python3 make_docs.py 2026-11-01: 「AIに昨日の続きをさせる」の make_docs.py を写して書き換えた(シリーズ「ひとりとAIのチーム」4回目) """ import sys, json, os, datetime sys.path.insert(0, '.') from narration import SEGS, parse NAME = "ハコブくんの声と絵" TITLE = "ハコブくんの声と絵は、どう作っているのか ― AIが候補を出し、人が見比べ・聞き比べて選ぶ" ROUND = 1 FJ = {"base": "基本", "smile": "小さな笑み", "surprise": "驚き", "doubt": "ジト目", "think": "目を閉じる", "trouble": "困り眉", "joy": ">▽<", "wink": "ウインク"} SEC = [("hook_koma", "0 フック"), ("title", "1 自己紹介"), ("question", "2 今日の問い"), ("answer", "3 結論と立場"), ("toc", "4 目次"), ("c1", "5 節1:絵を、どう描いているのか"), ("c2", "6 節2:声を、どう選んだのか"), ("c3", "7 節3:読み間違いを、どう直しているのか"), ("mitate", "8 見立て"), ("answer2", "9 問いへの回答・まとめ"), ("outro", "10 アウトロ")] idx = {o['i']: o for o in json.load(open('tts/index.json'))} if os.path.exists('tts/index.json') else {} rows, n, t, done, first, last = [], 0, 0.0, set(), {}, {} for k, s in enumerate(SEGS): sc, f, text, p = parse(s) for key, name in SEC: if sc == key and name not in done: rows.append(("sec", name, t)); done.add(name) o = idx.get(k) t += (o['dur'] + o['pause']) if o else 0 if text: n += 1 first.setdefault(sc, n); last[sc] = n rows.append(("line", n, f, sc, text)) def R(*scs): return "・".join((f"S{first[x]:03d}〜S{last[x]:03d}" if first[x] != last[x] else f"S{first[x]:03d}") for x in scs if x in first) # 読み物の台本 out = [f"# 台本:{TITLE}", "", "話し手はハコブくん(エイイチは三人称)。各行は「文番号|表情|場面|字幕の文」。字幕の「|」は、読み上げは1文のまま字幕だけ次の枚に替える位置。", ""] for r in rows: if r[0] == "sec": m, ss = divmod(int(r[2]), 60); out += ["", f"## {r[1]}" + (f"({m}:{ss:02d}〜)" if idx or r[1] == "0 フック" else ""), ""] else: out.append(f"- S{r[1]:03d}|{FJ[r[2]]}|{r[3]}|{r[4]}") if idx: m, ss = divmod(int(t), 60) out += ["", f"全体の長さ(いまの音声):{m}分{ss:02d}秒"] open(f"台本_{NAME}.md", "w").write("\n".join(out) + "\n") # codex 敵対的検証の依頼 body = [] for r in rows: body.append(f"\n### {r[1]}\n" if r[0] == "sec" else f"S{r[1]:03d} {r[4].replace('|', '')}") md = f"""# 敵対的検証依頼:YouTube台本「{TITLE}」 ## あなたへの依頼 これから公開する解説動画(見込み 約9分)の台本を、**この台本を論破するつもりで**検証してください。褒める必要はありません。見落としを1つでも多く見つけることが目的です。 - チャンネル:フィジカルAI解説|Pixels to Motors。書き手はエイイチ(台本の文は主に Claude が書き、エイイチが確定する)。本業のデザイナーをしながら、ロボティクスの研究と開発をしている個人 - 話し手:ナレーションはキャラクターのハコブくん(AI 音声)。エイイチを三人称で呼ぶ - 視聴者:ロボティクスに関心のある経営者・PM・マネージャー・開発者 - シリーズ「ひとりとAIのチーム」の4本目(全6回)。エイイチが研究と発信を1人で続けるために実際にやっている AI の使い方を、記録をもとに見せる。AI 活用の相談の看板にはしない。この回は、案内役ハコブくん自身の「絵と声」の作り方。シリーズの中の軽い回 - 台本の結論:AI は候補を出し、AI も確かめるが、最後に選んで通すのは人。絵は Claude が1コマずつ指示の文を書き、Gemini が描き、決まりの表(チェック項目)と人の目で確かめる(今日の失敗=人の腕が3本)。声は ElevenLabs のボイスデザインで説明文から候補を作り、人が聞き比べて決めた。読み間違いは見つけるたびに直しの表に足す。手間は「1から作る」作業はしていないが、選ぶ・確かめる手間は残っている - 材料はエイイチ自身の記録(マンガのチェック項目と過去の間違いの表・声の候補の記録・動画制作の決まり video_rules.md・台本の読みの直しの表)。あなたは記録を直接は開けないので、**下の記録の写しと台本の文が合っているか・記録から言える範囲を越えていないか**を中心に見てください。ElevenLabs のボイスデザインと Gemini の画像生成の一般的な説明は、公式のページをウェブで確かめてください - 書く前に、台本を書いたのとは別のエージェントに、記録と1文ずつ突き合わせてもらった(直したこと: 結論を「間違いを見つけるのは人」から「AIも確かめるが、最後に選んで通すのは人」に(過去の間違いの表22行のうち4行は別のAIが見つけていた)・表の行数20→22・「130話を超えた」→日本語版99話(番号は飛んでいる)・体は動画の1コマでなく作り直した絵・「球」の読み違いは別の回・14文は1本目の動画の冒頭・別のAI→別の会話のAI・「いちばん多かった」→「いちばん手こずった」) - エイイチ本人の実感の文({R('honne_voice','honne_check')}・{R('mitate_fear','mitate_job')} の一部)は本人の答えで、事実として裏付けを探す対象ではありません。置いた場所と、事実の文を弱めていないかは見てください - 検証日:{datetime.date.today().isoformat()}。参照できない場合は「未確認」と明記し、推測で OK を出さないでください - **これは{ROUND}回目の検証です。** ## 検証してほしい観点 ### A. 事実 A1. 下の記録の写しと台本の各文が合っているか。特に数({R('fail_arm','ledger','read_table','vd_text','face','cast','manga')}) A2. ElevenLabs・Gemini の説明({R('vd','manga_flow')})が、公式の説明の範囲か。製品の比べ合いや宣伝に聞こえないか ### B. 論理 B1. 問い({R('question')})と答え({R('answer','answer2')})がそろっているか B2. 「人が選ぶなら手間は減っていないのでは」という反論({R('stance','less_more')})に、記録から言える範囲で答えているか。減った・増えたと言い過ぎていないか B3. 「最後に選んで通すのは人」と言うのに、AI が見つけた間違いがあることと矛盾しないか ### C. 抜けている反論・視点 C1. 生成AIの絵と声を使うことへの、権利・利用条件・表示(概要欄に「AI音声」「マンガの絵は生成AI」と書く運用)の視点が抜けていないか。ただし台本で扱うかはエイイチが決める C2. 1人の体制の話を、チームや会社にそのまま当てはめていないか ### D. 言い方 D1. 断定が強すぎる文、逆に曖昧で意味のない文 D2. 冗長な所。いまの見込みは約9分(字幕の本文で約3,600字) D3. 軽い一言({R('ledger','quiz_ans','hook_q')} の一部)が、事実の文や但し書きを弱めていないか ## 回答の書式 指摘ごとに次の形で書いてください。重大なものから順に並べてください。