<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gemini | imakat.com</title>
	<atom:link href="https://imakat.com/tag/gemini/feed/" rel="self" type="application/rss+xml" />
	<link>https://imakat.com</link>
	<description>工夫と改善で人生をちょっと豊かに</description>
	<lastBuildDate>Tue, 27 Oct 2026 21:05:31 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://i0.wp.com/imakat.com/wp-content/uploads/2023/07/cropped-80d64ecd340db4e2ca3224859b04caed.png?fit=32%2C32&#038;ssl=1</url>
	<title>Gemini | imakat.com</title>
	<link>https://imakat.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">160909258</site>	<item>
		<title>【AI活用】第４弾！コード生成エコシステムを成功させる3つのポイント！ 〜AI連携をハンドメイドする〜</title>
		<link>https://imakat.com/2026/09/29/29847/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Tue, 29 Sep 2026 01:36:10 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[ローカルLLM]]></category>
		<category><![CDATA[Gemini]]></category>
		<category><![CDATA[Google AI Studio]]></category>
		<category><![CDATA[gemini notebook]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=29847</guid>

					<description><![CDATA[はじめに&#160; まずは、動画をご覧ください。 生成AIブームがここ数年急激に発展してきているわけですが、生成AIを個人が利用する場合は、ネットワークを通じてクラウドを使うしかないだろうと最初は見ていましたが、 最近 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading"><strong>はじめに</strong>&nbsp;</h2>



<p class="wp-block-paragraph">まずは、動画をご覧ください。</p>


<div class="sc-dynamic-embed">
  <style>
  /* リンクの見た目を整える */
  .sc-dynamic-embed .sc-link-container { 
      display: flex; 
      margin-bottom: 10px; 
      flex-wrap: wrap; 
      align-items: center; 
  }
  .sc-dynamic-embed .sc-link { margin-bottom: 0; }
  .sc-dynamic-embed .sc-link a {
    font-size: 15px; 
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  @media (max-width: 500px) {
    .sc-dynamic-embed .sc-link a { font-size: 13px; }
  }

  .sc-dynamic-embed .imk-line {
      display: inline-block;
      width: 100%;
      border-radius: 2px;
      transition: background-color 0.1s;
  }

  .sc-dynamic-embed #subtitleOverlay,
  .sc-dynamic-embed #scSubtitleOverlay,
  .sc-dynamic-embed .overlay-cue,
  .sc-dynamic-embed .band {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
  }
  </style>

  <div class="sc-link-container">
    <p class="sc-link">
      <!-- ★環境依存排除：固定ドメインをルート相対パスへ置換完了 -->
      <a href="/ds62/?drid=107" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <!-- ★環境依存排除：[dynamic_external_html] にルート相対パスを指定し、functions.phpにURL動的解決を委ねる設計 -->
  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=oEmTdcOT.png" playsinline preload="none" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=J4mfNzqT.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=QGMwkTi0.vtt" label="日本語" srclang="ja" kind="subtitles"></video></div><div class="dr5emd-sublist"><details translate="yes"><summary translate="yes">字幕一覧(クリック)</summary> <p translate="yes">
(<a href="#" class="imk-cue" data-seek="0:00" translate="no">00:00:00</a>) 〜コード生成エコシステムを成功させる３つのポイント〜<br>
(<a href="#" class="imk-cue" data-seek="0:08" translate="no">00:00:08</a>) これまで<br>
(<a href="#" class="imk-cue" data-seek="0:09" translate="no">00:00:09</a>) コーディングを生成AIで行う方法を<br>
(<a href="#" class="imk-cue" data-seek="0:13" translate="no">00:00:13</a>) 記事にしてきたことがあるわけですが、<br>
(<a href="#" class="imk-cue" data-seek="0:17" translate="no">00:00:17</a>) 今回は一応一つの節目というか、<br>
(<a href="#" class="imk-cue" data-seek="0:20" translate="no">00:00:20</a>) 区切りとして整理しておきたいと思います。<br>
(<a href="#" class="imk-cue" data-seek="0:25" translate="no">00:00:25</a>) 生成AIには代表として<br>
(<a href="#" class="imk-cue" data-seek="0:28" translate="no">00:00:28</a>) ChatGPT、<br>
(<a href="#" class="imk-cue" data-seek="0:30" translate="no">00:00:30</a>) Claude、<br>
(<a href="#" class="imk-cue" data-seek="0:32" translate="no">00:00:32</a>) Geminiの3つがあります。<br>
(<a href="#" class="imk-cue" data-seek="0:34" translate="no">00:00:34</a>) 私は成り行き上、<br>
(<a href="#" class="imk-cue" data-seek="0:37" translate="no">00:00:37</a>) Geminiを今のところ使っています。<br>
(<a href="#" class="imk-cue" data-seek="0:41" translate="no">00:00:41</a>) それからクラウドかローカルかという選択の問題もありますが、<br>
(<a href="#" class="imk-cue" data-seek="0:48" translate="no">00:00:48</a>) 今回の3つのキモに関しては、<br>
(<a href="#" class="imk-cue" data-seek="0:51" translate="no">00:00:51</a>) 両方に共通だと思っています。<br>
(<a href="#" class="imk-cue" data-seek="0:56" translate="no">00:00:56</a>) その3つとは、「知識ソースを蓄える」、<br>
(<a href="#" class="imk-cue" data-seek="1:00" translate="no">00:01:00</a>) 「秘匿化を行う」、<br>
(<a href="#" class="imk-cue" data-seek="1:02" translate="no">00:01:02</a>) 「迅速なエラー対策」ということなのですが、<br>
(<a href="#" class="imk-cue" data-seek="1:07" translate="no">00:01:07</a>) 一般に考えたAIの活用ということなら、<br>
(<a href="#" class="imk-cue" data-seek="1:11" translate="no">00:01:11</a>) 「知識ソース」必須ということだけで十分かもしれません。<br>
(<a href="#" class="imk-cue" data-seek="1:17" translate="no">00:01:17</a>) 私の場合コーディングも非常に比重が大きいので、<br>
(<a href="#" class="imk-cue" data-seek="1:22" translate="no">00:01:22</a>) さらにそこに「秘匿化」と<br>
(<a href="#" class="imk-cue" data-seek="1:24" translate="no">00:01:24</a>) 「エラー対策」が追加されてきます。<br>
(<a href="#" class="imk-cue" data-seek="1:28" translate="no">00:01:28</a>) 1つ目の「知識ソース」です。<br>
(<a href="#" class="imk-cue" data-seek="1:31" translate="no">00:01:31</a>) 私は図書館に例えています。<br>
(<a href="#" class="imk-cue" data-seek="1:38" translate="no">00:01:38</a>) まず「知識ソースの基盤」です。<br>
(<a href="#" class="imk-cue" data-seek="1:42" translate="no">00:01:42</a>) 大手IT企業だと社内Wiki、<br>
(<a href="#" class="imk-cue" data-seek="1:46" translate="no">00:01:46</a>) 全社ポータルというような箱というか入れものをですね、<br>
(<a href="#" class="imk-cue" data-seek="1:51" translate="no">00:01:51</a>) 情報システム部が用意してくれるでしょう。<br>
(<a href="#" class="imk-cue" data-seek="1:54" translate="no">00:01:54</a>) 一方、私は<br>
(<a href="#" class="imk-cue" data-seek="1:56" translate="no">00:01:56</a>) GeminiのNotebookに<br>
(<a href="#" class="imk-cue" data-seek="1:58" translate="no">00:01:58</a>) 自分用・公開用の図書館を用意します。<br>
(<a href="#" class="imk-cue" data-seek="2:04" translate="no">00:02:04</a>) 次に「コンテキストの管理」、<br>
(<a href="#" class="imk-cue" data-seek="2:07" translate="no">00:02:07</a>) つまり記事の引き出し方ですが、<br>
(<a href="#" class="imk-cue" data-seek="2:10" translate="no">00:02:10</a>) 大手IT企業はベクターDBとか<br>
(<a href="#" class="imk-cue" data-seek="2:13" translate="no">00:02:13</a>) 本格的なRAGシステムを使っています。<br>
(<a href="#" class="imk-cue" data-seek="2:19" translate="no">00:02:19</a>) RAGは記事をコンピュータが理解しやすい形に<br>
(<a href="#" class="imk-cue" data-seek="2:22" translate="no">00:02:22</a>) 変換したもの。<br>
(<a href="#" class="imk-cue" data-seek="2:25" translate="no">00:02:25</a>) 料理で言うところの仕込み、<br>
(<a href="#" class="imk-cue" data-seek="2:28" translate="no">00:02:28</a>) あるいは御膳立てというのですか、<br>
(<a href="#" class="imk-cue" data-seek="2:31" translate="no">00:02:31</a>) その種の物と捉えてください。<br>
(<a href="#" class="imk-cue" data-seek="2:34" translate="no">00:02:34</a>) 一方、私はNotebookを使いますが、<br>
(<a href="#" class="imk-cue" data-seek="2:38" translate="no">00:02:38</a>) これは幸いにもRAGシステムが<br>
(<a href="#" class="imk-cue" data-seek="2:40" translate="no">00:02:40</a>) 使われていますので、<br>
(<a href="#" class="imk-cue" data-seek="2:42" translate="no">00:02:42</a>) そのまま役に立ちます。<br>
(<a href="#" class="imk-cue" data-seek="2:47" translate="no">00:02:47</a>) 次に「情報区分の統制」というところですが、<br>
(<a href="#" class="imk-cue" data-seek="2:51" translate="no">00:02:51</a>) 私はtxtファイルを実行用の<br>
(<a href="#" class="imk-cue" data-seek="2:55" translate="no">00:02:55</a>) exe.txtファイルと、<br>
(<a href="#" class="imk-cue" data-seek="2:57" translate="no">00:02:57</a>) 公開用の<br>
(<a href="#" class="imk-cue" data-seek="2:59" translate="no">00:02:59</a>) pub.txtファイルにシンプルに区分けしています。<br>
(<a href="#" class="imk-cue" data-seek="3:04" translate="no">00:03:04</a>) 具体的には目的別に図書館を分けています。<br>
(<a href="#" class="imk-cue" data-seek="3:10" translate="no">00:03:10</a>) 自分用imakat図書館、<br>
(<a href="#" class="imk-cue" data-seek="3:12" translate="no">00:03:12</a>) 公開用imakat図書館。<br>
(<a href="#" class="imk-cue" data-seek="3:15" translate="no">00:03:15</a>) それからソースファイルの厳格な<br>
(<a href="#" class="imk-cue" data-seek="3:18" translate="no">00:03:18</a>) 区分ルールをつけています。<br>
(<a href="#" class="imk-cue" data-seek="3:22" translate="no">00:03:22</a>) コード類、<br>
(<a href="#" class="imk-cue" data-seek="3:24" translate="no">00:03:24</a>) それからimakatブログ、<br>
(<a href="#" class="imk-cue" data-seek="3:26" translate="no">00:03:26</a>) それから備忘録の3種類がありますけども、<br>
(<a href="#" class="imk-cue" data-seek="3:30" translate="no">00:03:30</a>) コードは<br>
(<a href="#" class="imk-cue" data-seek="3:32" translate="no">00:03:32</a>) 実行用コードと公開用コードがあります。<br>
(<a href="#" class="imk-cue" data-seek="3:36" translate="no">00:03:36</a>) imakatブログは<br>
(<a href="#" class="imk-cue" data-seek="3:38" translate="no">00:03:38</a>) ブログの全記事をテキスト化しています。<br>
(<a href="#" class="imk-cue" data-seek="3:43" translate="no">00:03:43</a>) 備忘録ですが、<br>
(<a href="#" class="imk-cue" data-seek="3:45" translate="no">00:03:45</a>) 内部備忘録と<br>
(<a href="#" class="imk-cue" data-seek="3:47" translate="no">00:03:47</a>) 外部備忘録があります。<br>
(<a href="#" class="imk-cue" data-seek="3:50" translate="no">00:03:50</a>) 内部備忘録は個人情報とか<br>
(<a href="#" class="imk-cue" data-seek="3:52" translate="no">00:03:52</a>) 外部秘にしたい記録が含まれてますので、<br>
(<a href="#" class="imk-cue" data-seek="3:57" translate="no">00:03:57</a>) 今後セキュリティに強いAppleのAIに含めることになると思います。<br>
(<a href="#" class="imk-cue" data-seek="4:02" translate="no">00:04:02</a>) とりあえずは使いません。<br>
(<a href="#" class="imk-cue" data-seek="4:05" translate="no">00:04:05</a>) それから外部備忘録ですが、これが<br>
(<a href="#" class="imk-cue" data-seek="4:08" translate="no">00:04:08</a>) 作業記録とか<br>
(<a href="#" class="imk-cue" data-seek="4:10" translate="no">00:04:10</a>) チャットログ、<br>
(<a href="#" class="imk-cue" data-seek="4:12" translate="no">00:04:12</a>) 技術アイデアなど、<br>
(<a href="#" class="imk-cue" data-seek="4:14" translate="no">00:04:14</a>) そういった知識とか経験の蓄積として<br>
(<a href="#" class="imk-cue" data-seek="4:17" translate="no">00:04:17</a>) 自分用の図書館にリンクさせ、<br>
(<a href="#" class="imk-cue" data-seek="4:20" translate="no">00:04:20</a>) AIの頭脳にしていきます。<br>
(<a href="#" class="imk-cue" data-seek="4:23" translate="no">00:04:23</a>) この外部備忘録をNotebookに入れていくことになります。<br>
(<a href="#" class="imk-cue" data-seek="4:31" translate="no">00:04:31</a>) 次に2つ目に大事なのが「秘匿化」です。<br>
(<a href="#" class="imk-cue" data-seek="4:35" translate="no">00:04:35</a>) 個人情報が外に漏れると大きな損失につながってきます。<br>
(<a href="#" class="imk-cue" data-seek="4:42" translate="no">00:04:42</a>) プログラムを動かす秘密キーやパスワードは、<br>
(<a href="#" class="imk-cue" data-seek="4:48" translate="no">00:04:48</a>) 運用上でリミッターをかけて暴走を止めることはできますが、<br>
(<a href="#" class="imk-cue" data-seek="4:53" translate="no">00:04:53</a>) それでもその間、無駄な損失を拡大させてしまいます。<br>
(<a href="#" class="imk-cue" data-seek="5:00" translate="no">00:05:00</a>) 「機密情報の保管」ですが、大手IT企業ではクラウド金庫サービスで厳格に運用されます。<br>
(<a href="#" class="imk-cue" data-seek="5:11" translate="no">00:05:11</a>) 私としては秘密情報はローカルの.envファイルに隔離させます。<br>
(<a href="#" class="imk-cue" data-seek="5:19" translate="no">00:05:19</a>) 「パラメーターの払い出し」では、<br>
(<a href="#" class="imk-cue" data-seek="5:23" translate="no">00:05:23</a>) 大手IT企業は専任のセキュリティシステムが、<br>
(<a href="#" class="imk-cue" data-seek="5:29" translate="no">00:05:29</a>) 一定時間だけ有効な合鍵を発行して認可するような仕組みになっています。<br>
(<a href="#" class="imk-cue" data-seek="5:36" translate="no">00:05:36</a>) 私としてはNotebookを管理塔として、パラメーターのみをAIに渡すようにしています。<br>
(<a href="#" class="imk-cue" data-seek="5:45" translate="no">00:05:45</a>) 「プライバシー対策」では、大手IT企業は<br>
(<a href="#" class="imk-cue" data-seek="5:51" translate="no">00:05:51</a>) GitGuardianなどで監視して自動的な遮断を行うようになっています。<br>
(<a href="#" class="imk-cue" data-seek="5:58" translate="no">00:05:58</a>) 私としては誰かとコーディングの共同作業をすることもないので、<br>
(<a href="#" class="imk-cue" data-seek="6:04" translate="no">00:06:04</a>) GitHubまでは使わず、ローカルのテキストファイルで管理して、<br>
(<a href="#" class="imk-cue" data-seek="6:09" translate="no">00:06:09</a>) その中で固有名詞のマスキングを行なっています。<br>
(<a href="#" class="imk-cue" data-seek="6:16" translate="no">00:06:16</a>) 具体的には「ハード秘匿化」ですが、<br>
(<a href="#" class="imk-cue" data-seek="6:19" translate="no">00:06:19</a>) 危険度の高い個人情報やキー情報は、<br>
(<a href="#" class="imk-cue" data-seek="6:23" translate="no">00:06:23</a>) コードの中には直接には書かないようにしています。<br>
(<a href="#" class="imk-cue" data-seek="6:28" translate="no">00:06:28</a>) もしセキュリティの弱いAI Studioなどで作業中に秘匿化が必要な場合は、<br>
(<a href="#" class="imk-cue" data-seek="6:36" translate="no">00:06:36</a>) 必ずNotebookにパラメーター化を依頼して、<br>
(<a href="#" class="imk-cue" data-seek="6:42" translate="no">00:06:42</a>) Notebookからは設定されたパラメーターだけを返答するようにします。<br>
(<a href="#" class="imk-cue" data-seek="6:48" translate="no">00:06:48</a>) 「ソフト秘匿化」については、これを知られても困るようなことはほとんどないのですが、<br>
(<a href="#" class="imk-cue" data-seek="6:55" translate="no">00:06:55</a>) マスキングしておきたいような情報、例えば本名のようなものでしょうか、<br>
(<a href="#" class="imk-cue" data-seek="7:02" translate="no">00:07:02</a>) これは自分で任意に設定できるようにしてあります。<br>
(<a href="#" class="imk-cue" data-seek="7:07" translate="no">00:07:07</a>) それから最後の3つ目に大事なのが「エラー対策」です。<br>
(<a href="#" class="imk-cue" data-seek="7:13" translate="no">00:07:13</a>) 実はこれが一番難しいです。<br>
(<a href="#" class="imk-cue" data-seek="7:18" translate="no">00:07:18</a>) と言いますのは、私自身にとって、<br>
(<a href="#" class="imk-cue" data-seek="7:23" translate="no">00:07:23</a>) まず起きている現象がエラーなのか何なのか分からないということ、<br>
(<a href="#" class="imk-cue" data-seek="7:29" translate="no">00:07:29</a>) エラーである場合、何のプログラムが起因してるかが分からないことです。<br>
(<a href="#" class="imk-cue" data-seek="7:36" translate="no">00:07:36</a>) 病気と同じで、最初に総合診断をしてもらって専門医に行き、<br>
(<a href="#" class="imk-cue" data-seek="7:44" translate="no">00:07:44</a>) 難病なら大病院に行くというような移動が生じるわけですね。<br>
(<a href="#" class="imk-cue" data-seek="7:51" translate="no">00:07:51</a>) 今の私のようなクラウド型AIの利用の場合は、<br>
(<a href="#" class="imk-cue" data-seek="7:58" translate="no">00:07:58</a>) 初期の総合診断はGemini、<br>
(<a href="#" class="imk-cue" data-seek="8:02" translate="no">00:08:02</a>) 専門医の選定はNotebook、<br>
(<a href="#" class="imk-cue" data-seek="8:06" translate="no">00:08:06</a>) 簡単な治療ならNotebook、<br>
(<a href="#" class="imk-cue" data-seek="8:10" translate="no">00:08:10</a>) 難病ならAI Studioという運びになります。<br>
(<a href="#" class="imk-cue" data-seek="8:14" translate="no">00:08:14</a>) ただ私としては、初期の総合診断から簡単な治療までは、<br>
(<a href="#" class="imk-cue" data-seek="8:21" translate="no">00:08:21</a>) 地元の医者、つまりローカルAIで済ませて、<br>
(<a href="#" class="imk-cue" data-seek="8:25" translate="no">00:08:25</a>) 難病の場合は専門的な大病院、<br>
(<a href="#" class="imk-cue" data-seek="8:30" translate="no">00:08:30</a>) つまりクラウドAIというような棲み分けをしたいと思っています。<br>
(<a href="#" class="imk-cue" data-seek="8:39" translate="no">00:08:39</a>) それでは最後におまけです。<br>
(<a href="#" class="imk-cue" data-seek="8:43" translate="no">00:08:43</a>) Notebookでコーディングを行うことも可能ですが、<br>
(<a href="#" class="imk-cue" data-seek="8:47" translate="no">00:08:47</a>) 画面に表示されたコードやコマンドをそのままコピペして<br>
(<a href="#" class="imk-cue" data-seek="8:52" translate="no">00:08:52</a>) ターミナルで実行したり、実行ファイルに保存したりすることになります。<br>
(<a href="#" class="imk-cue" data-seek="9:00" translate="no">00:09:00</a>) その時に単純なコピペではですね、この様に改行なしのベタ書きになってしまいます。<br>
(<a href="#" class="imk-cue" data-seek="9:10" translate="no">00:09:10</a>) そこで、3回クリックした時の3回目を押したまま末尾までもってくる。<br>
(<a href="#" class="imk-cue" data-seek="9:18" translate="no">00:09:18</a>) それをコピーする。<br>
(<a href="#" class="imk-cue" data-seek="9:24" translate="no">00:09:24</a>) そして、それを貼り付けると、<br>
(<a href="#" class="imk-cue" data-seek="9:28" translate="no">00:09:28</a>) ということで正常にペーストすることができます。<br>
(<a href="#" class="imk-cue" data-seek="9:35" translate="no">00:09:35</a>) すると、元のままでペーストされます。<br>
(<a href="#" class="imk-cue" data-seek="9:38" translate="no">00:09:38</a>) 以上です。<br>
(<a href="#" class="imk-cue" data-seek="9:43" translate="no">00:09:43</a>) 〜コード生成エコシステムを成功させる3つのポイント〜でした。<br>
</p> </details>
<style>
details { font: 16px "Open Sans", Calibri, sans-serif; width: 100%; }
details > summary { padding: 2px 6px; width: 100%; background-color: #ddd; border: none; box-shadow: 3px 3px 4px black; cursor: pointer; list-style: none; }
details > p { font: 14px "Open Sans", Calibri, sans-serif; height:150px; overflow: scroll; background-color: #EDF7FF; padding: 2px 6px; margin: 0; box-shadow: 3px 3px 4px black; }
</style>
</div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

  <script>
  (function(){
    var me = document.currentScript;
    var wrapper = me ? me.closest('.sc-dynamic-embed') : null;

    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video) return false; 
      
      if (video.dataset.subInit === 'true') return true; 
      video.dataset.subInit = 'true';

      var oldOverlay = target.querySelector('#subtitleOverlay') || target.querySelector('#scSubtitleOverlay');
      if (oldOverlay) {
          oldOverlay.style.setProperty('display', 'none', 'important');
          oldOverlay.innerHTML = ''; 
      }

      // 全画面・PiP・iOS全画面の判定（dr52.php準拠＋Safari presentationMode完全対応）
      function isSpecialMode() {
        var fsEl = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
        var isFs = !!fsEl;
        var isWebkitFs = (video.webkitPresentationMode === "fullscreen") || !!video.webkitDisplayingFullscreen;
        var isPiP = !!(document.pictureInPictureElement && document.pictureInPictureElement === video) || (video.webkitPresentationMode === "picture-in-picture");
        return isFs || isWebkitFs || isPiP;
      }

      // 字幕トラックの表示/非表示を更新
      function updateTrackMode() {
        var hasList = (listContainer !== null);
        var desiredMode = (isSpecialMode() || !hasList) ? "showing" : "hidden";
        try {
          if (video.textTracks && video.textTracks.length > 0) {
            for (var i = 0; i < video.textTracks.length; i++) {
              var track = video.textTracks[i];
              if ((track.kind === 'subtitles' || track.kind === 'captions') && track.mode !== desiredMode) {
                track.mode = desiredMode;
              }
            }
          }
        } catch(e) {}
      }

      // 初回の反映
      updateTrackMode();

      // 各種全画面・PiP切り替えイベントの即時検知リスナーを登録（video本体・document双方を監視）
      ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange'].forEach(function(evtName) {
        document.addEventListener(evtName, updateTrackMode, false);
        video.addEventListener(evtName, updateTrackMode, false);
      });
      video.addEventListener('webkitbeginfullscreen', updateTrackMode, false);
      video.addEventListener('webkitendfullscreen', updateTrackMode, false);
      video.addEventListener('webkitpresentationmodechanged', updateTrackMode, false);
      video.addEventListener('enterpictureinpicture', updateTrackMode, false);
      video.addEventListener('leavepictureinpicture', updateTrackMode, false);
      video.addEventListener('play', updateTrackMode, false);
      video.addEventListener('pause', updateTrackMode, false);

      // 字幕一覧が存在する場合のみ、リストのフォーマット処理を行う
      if (listContainer) {
          var detailsEl = target.querySelector("details");
          if (detailsEl) {
              detailsEl.open = true; 
              var summaryEl = detailsEl.querySelector("summary");
              if (summaryEl) summaryEl.textContent = "字幕(シーン)はここをクリック";
          }

          if (!listContainer.dataset.formatted) {
              var html = listContainer.innerHTML;
              var lines = html.split(/<br\s*\/?>/i);
              var newHtml = "";
              for(var j=0; j<lines.length; j++) {
                  if(lines[j].trim() === "") continue;
                  newHtml += "<span class='imk-line'>" + lines[j] + "</span><br>";
              }
              listContainer.innerHTML = newHtml;
              listContainer.dataset.formatted = "true";
          }

          var rootSublist = target.querySelector(".dr5-sublist") || listContainer.parentElement;
          if (rootSublist) {
            rootSublist.addEventListener("click", function(e){
              var a = e.target.closest && e.target.closest("a.imk-cue[data-seek]");
              if(!a) return;
              e.preventDefault();
              var ts = a.getAttribute("data-seek");
              if(!ts) return;
              var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
              var sec = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2]: null);
              if(sec==null) return;
              try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
            });
          }
      }

      // 再生中（時間進行時）の追従とハイライト更新
      video.addEventListener("timeupdate", function(){
        updateTrackMode();

        var hasList = (listContainer !== null);
        if (!hasList) return;

        var cues = listContainer.querySelectorAll("a.imk-cue");
        if(cues.length === 0) return;
        var cur = video.currentTime;
        var activeA = null;

        for(var i=0; i<cues.length; i++){
            var ts = cues[i].getAttribute("data-seek");
            if(!ts) continue;
            var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
            var t = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

        if(activeA){
            var activeLine = activeA.closest(".imk-line");
            if(!activeLine) activeLine = activeA;

            if(activeLine.classList.contains("active-hl")) return;

            var allLines = listContainer.querySelectorAll(".imk-line");
            for(var k=0; k<allLines.length; k++) {
                allLines[k].classList.remove("active-hl");
                allLines[k].removeAttribute("style"); 
            }
            var allLinks = listContainer.querySelectorAll("a");
            for(var m=0; m<allLinks.length; m++) {
                allLinks[m].classList.remove("active-hl");
                allLinks[m].removeAttribute("style"); 
            }

            activeLine.classList.add("active-hl");
            activeLine.style.setProperty("background-color", "#ffff00", "important");
            activeLine.style.setProperty("color", "red", "important");
            activeLine.style.setProperty("font-weight", "normal", "important");
            
            var newLinks = activeLine.querySelectorAll("a");
            for(var n=0; n<newLinks.length; n++) {
                newLinks[n].style.setProperty("color", "red", "important");
                newLinks[n].style.setProperty("text-decoration", "none", "important");
            }

            if(listContainer.offsetParent !== null){
                var containerRect = listContainer.getBoundingClientRect();
                var activeRect = activeLine.getBoundingClientRect();
                var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (activeLine.clientHeight / 2);
                listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
            }
        }
      });

      return true;
    }

    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    if (!window.scStopAndGo) {
      window.scStopAndGo = function(event, link){
        try{
          var mediaEls = document.querySelectorAll('video, audio');
          mediaEls.forEach(function(m){
            try{
              if (!m.paused) m.pause();
              if (document.pictureInPictureElement === m && document.exitPictureInPicture) {
                document.exitPictureInPicture().catch(function(){});
              }
            }catch(e){}
          });
        }finally{
          event.preventDefault();
          setTimeout(function(){
            if (link.target === '_blank') {
              window.open(link.href, '_blank');
            } else {
              window.location.href = link.href;
            }
          }, 50);
        }
        return false;
      };
    }
  })();
  </script>
</div>



<p class="wp-block-paragraph">生成AIブームがここ数年急激に発展してきているわけですが、生成AIを個人が利用する場合は、ネットワークを通じてクラウドを使うしかないだろうと最初は見ていましたが、</p>



<p class="wp-block-paragraph">最近はそれをMac mini上のローカルLLMで行おうとする人も増えています。これは、かつて流行した「自宅Webサーバー」を思い起こさせます。しかし「自宅Webサーバー」ブームは短命でした。というのは、機器のメンテナンスやウイルス感染、災害リスクが重くのしかかって個人が自宅で抱えていくのにはちょっと無理な発想だったわけです。</p>



<p class="wp-block-paragraph">ローカルとクラウドの長所短所を考え合わせれば、やはりハイブリッド化していくのが合理的に思えてきますね。</p>



<p class="wp-block-paragraph">私の場合ですが、今のところはクラウドだけを使っています。どの大手のAIにも移行できるように、ソースはtxtファイルをベースにして言語はPythonなどの一般的な言語を中心にしています。現在は成り行き上、Googleを使っています。Googleは何でも揃うのでラクと言うことでしょうか。Notebook・Gemini・Google AI Studioを連携させています。これらをうまく活用するための3つのポイントについて、<strong>大手IT企業のアプローチとの対比</strong>を交えながら解説します。</p>



<h2 class="wp-block-heading"><strong>ポイント1：Gemini Notebookに「知識」を蓄える</strong></h2>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=ncOHywu5.jpeg" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=ncOHywu5.jpeg" alt=""/></a></figure>



<p class="wp-block-paragraph">AIを開発パートナーとして機能させるための第一歩は、例えばNotebookへ前提知識（コンテキスト）を溜め込むことだと思います。溜め込みを判断するのはあくまで私です。生成AIに勝手に任せることはしません。やっぱり自分が中身を知っていることは重要ですから。私が生成AIによるコーディングを実行できたのも、imakatブログへの投稿の蓄積、自前でネットから拾い上げながらコツコツ作ってきたプログラムコードの蓄積、その他もろもろ、それらを知識ソースとして投入できたことが非常に大きいです。<br>古臭いと感じるかもしれませんが、年月かけてブログ投稿を積み重ねるのが役に立つと思います。SNSは瞬間の出来事の切り取りと感じた印象だけを記録するので知見の蓄積としてはちょっと弱い、やっぱりブログがいいと思います。始めるのは若ければ若いほどいいと思います。身近な改善や経験を備忘録のつもりで書いていく、記事の投稿の目標は、ばらつきはあるとしても月１点以上がいいと思います。大事な事は職業上の秘密には絶対に触れないことです。私としてはこのWordPressのブログをコツコツと続けてきて本当によかったと感じています。</p>



<p class="wp-block-paragraph">Notebookを用途に合わせて明確に区分し、知識資産を分類・配置します。</p>



<p class="wp-block-paragraph"><strong>大手IT企業と個人ハンドメイドの対比</strong></p>



<figure class="wp-block-table"><table class="has-border-color has-key-color-border-color has-fixed-layout" style="border-width:1px"><tbody><tr><td><strong>比較項目</strong></td><td><strong>大手IT企業の通常アプローチ</strong></td><td><strong>本エコシステムのハンドメイド手法</strong></td></tr><tr><td><strong>知識ソースの基盤</strong></td><td>社内Wiki（Confluence等）や全社ポータルを専任チームが運用・保守</td><td><strong>Notebookの用途別「図書館」</strong>（自分用／公開用）に直接集約</td></tr><tr><td><strong>コンテキスト管理</strong></td><td>ベクターDBや高額な社内RAGシステムをインフラ構築して検索</td><td><strong>ノートブックのソース投入機能</strong>を活用し、追加費用ゼロで即時参照</td></tr><tr><td><strong>情報区分の統制</strong></td><td>複雑なアクセス権限（ACL）と閲覧ロール設定によるアクセス制限</td><td><strong>exe.txt（実行用）／pub.txt（公開用）／内外備忘録の命名規則</strong>でシンプルに統制</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><strong>具体的な運用設計</strong></p>



<ul class="wp-block-list">
<li><strong>目的別に「図書館」を分ける</strong>
<ul class="wp-block-list">
<li><strong>自分用imakat図書館</strong>：日々の開発・ブログ記事執筆、メンテナンス・デバッグを行うためのプライベートな知識ベース。</li>



<li><strong>公開用imakat図書館</strong>：外部共有、ブログ記事発信、公開向けのオープンな知恵袋。</li>
</ul>
</li>



<li><strong>ソース（ファイル）の厳格な区分ルール</strong>
<ul class="wp-block-list">
<li><strong>実行用コード（exe.txt）</strong>：手元で実際に動作するコード。自分用図書館にのみ格納し、公開用には一切含めません。</li>



<li><strong>公開用コード（pub.txt）</strong>：後述のソフト秘匿化（サニタイズ）を施したコード。両方の図書館で共有します。</li>



<li><strong>imakatブログ（公開）.txt</strong>：オープンな技術ノウハウや趣味雑学他の発信記事。両方の図書館に配置します。</li>



<li><strong>外部備忘録.txt（※重要）</strong>：
<ul class="wp-block-list">
<li><strong>内部備忘録【内】</strong>：個人情報や個人的な日記など、外部秘にしたい記録（AI・Notebookには一切連携しない）。今後、セキュリティに強いAppleのAIに含めることになると思います。</li>



<li><strong>外部備忘録【外】</strong>：作業記録、試行錯誤のチャットログ、技術アイデアなど。知識や経験の蓄積として自分用図書館にリンクさせ、AIの頭脳を育てます。</li>
</ul>
</li>
</ul>
</li>
</ul>



<h2 class="wp-block-heading"><strong>ポイント2：ハード秘匿化するモジュールを組み込む</strong></h2>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=NgsIlwpv.jpeg" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=NgsIlwpv.jpeg" alt=""/></a></figure>



<p class="wp-block-paragraph">クラウド型生成AIにコードを渡す際、最も恐ろしいのが認証情報や特定ファイルIDの漏洩です。これを防ぐため、「二層秘匿化」を行いました。ただし、この秘匿化の登録もAIに任せるのではなく私が判断します。</p>



<p class="wp-block-paragraph"><strong>大手IT企業と個人ハンドメイドの対比</strong></p>



<figure class="wp-block-table"><table class="has-border-color has-key-color-border-color has-fixed-layout" style="border-width:1px"><tbody><tr><td><strong>比較項目</strong></td><td><strong>大手IT企業の通常アプローチ</strong></td><td><strong>本エコシステムのハンドメイド手法</strong></td></tr><tr><td><strong>機密情報の保管</strong></td><td>クラウド金庫サービス（AWS Secrets Manager, HashiCorp Vault等）を有料導入</td><td><strong>ローカルの .env ファイル</strong>に隔離し、外部アクセスを物理遮断</td></tr><tr><td><strong>パラメータの払い出し</strong></td><td>専任のセキュリティ基盤がトークンを動的発行・認可管理</td><td><strong>Notebookを管理塔</strong>とし、プロンプト指示でパラメータのみをAIに持ち帰らせる</td></tr><tr><td><strong>プライバシー対策</strong></td><td>リポジトリ監視ツール（GitGuardian等）によるコミット自動遮断</td><td><strong>ソフト秘匿化ルール</strong>により、公開用コード生成時に固有名詞を自動サニタイズ</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><strong>具体的な運用設計</strong></p>



<ul class="wp-block-list">
<li><strong>第1層：ハード秘匿化（実質的セキュリティ）</strong><strong><br></strong> スプレッドシートIDやAPIキーをコード内に直接ベタ書き（SPREADSHEET_F8_ID = &#8220;1_ABCDabcd&#8230;&#8221;）せず、ローカルの .env ファイルへ隔離します。コード側は、Pythonの場合、 os.getenv(&#8220;SPREADSHEET_F8_ID&#8221;) で環境変数から動的ロードする構成を標準化します。</li>



<li><strong>ハード秘匿化モジュールはNoteBookで一元管理</strong><strong><br></strong> 生成AIのカスタム指示に「プログラムを作成している最中に、秘匿情報の設定が必要になったら、NoteBookへ行って秘匿情報にパラメータを設定してもらってパラメータだけを持ち帰って来ること。」と設定しておきます。AIに直接生データを触らせず、Notebookが安全なパラメータ名だけをコード側に橋渡しします。</li>



<li><strong>第2層：ソフト秘匿化（見た目・見栄えの安全性）</strong><strong><br></strong> メールアドレスや氏名などの固有名詞は、認証突破に直結しなくてもコードに残ると不格好で不用心です。公開用コード（pub.txt）を出力する段階で、これらの文字列を安全にマスキングします。</li>
</ul>



<h2 class="wp-block-heading"><strong>ポイント3：エラー修正プロセスを確実に実行する</strong></h2>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=TlLuCaVF.jpeg" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=TlLuCaVF.jpeg" alt=""/></a></figure>



<p class="wp-block-paragraph">実は、エラーへの対処が一番難しいところです。２つの問題があります。一つは、時間が経つと、記憶も薄れ、このエラーはどのプログラムが関係していたのか思い出せなくなることです。突然のエラーは焦りまくるので尚更です。もう一つは、NoteBookが画像動画の解析能力がほとんどないことです。従って、エラー時につきものの、エラーのスクショはGeminiに解析してもらうことが入り口になります。ここは将来はNoteBookにその解析能力がつくことを期待するものですが。そうした得手不得手のある中で、強みを活かした連携フローを敷いてみました。</p>



<p class="wp-block-paragraph"><strong>大手IT企業と個人ハンドメイドの対比</strong></p>



<figure class="wp-block-table"><table class="has-border-color has-key-color-border-color has-fixed-layout" style="border-width:1px"><tbody><tr><td><strong>比較項目</strong></td><td><strong>大手IT企業の通常アプローチ</strong></td><td><strong>本エコシステムのハンドメイド手法</strong></td></tr><tr><td><strong>障害受付（一次切り分け）</strong></td><td>運用監視ツール（Datadog等）＋ヘルプデスク／一次運用オペレーター</td><td><strong>Geminiによる画像解析</strong>（エラー画面のスクショを投げるだけで即座に言語化）</td></tr><tr><td><strong>原因特定・影響調査</strong></td><td>構成管理DB（CMDB）の突合＋熟練アーキテクトによる設計書レビュー</td><td><strong>Notebookによる全コード台帳の横断検索</strong>＋修正指示書の自動起票</td></tr><tr><td><strong>修正・リファクタリング</strong></td><td>大規模リファクタリング専門チームによる設計・テスト・実装作業</td><td><strong>Google AI Studioの広大なコンテキスト長</strong>を活かした一括修正</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><strong>具体的な運用設計</strong></p>



<ul class="wp-block-list">
<li><strong>新規開発・改善のフロー</strong>
<ul class="wp-block-list">
<li><strong>NoteBookに相談</strong>：まずは知識が蓄積されているNoteBookで過去資産や影響範囲を照合。</li>



<li><strong>規模に応じた切り分け</strong>：軽微な内容はNoteBook内で完結。400行を超える大規模ロジックや複雑な構造刷新は、広大なコンテキスト長を持つ <strong>Google AI Studio</strong> へ引き継いで一気に生成します。</li>



<li><strong>秘匿化連携</strong>：コード生成の途中でキーやIDが必要になったら、常に横の「NoteBook（ハード秘匿化モジュール）」へ依頼してパラメータを取得します。</li>
</ul>
</li>



<li><strong>エラー修正のリレー</strong>
<ul class="wp-block-list">
<li><strong>Geminiにエラー画像を投入（一次受付・言語化）</strong>：画面スクショをGeminiに渡すだけで、根本原因や関連キーワードを正確にテキスト化（短い修正ならそのままGeminiで修正完了）。</li>



<li><strong>NoteBookに投げてファイル特定＆指示書作成（司令塔）</strong>：言語化されたキーワードをもとにNoteBookが全コード（exe.txt等）を横断検索し、「該当ファイルの特定」と「AI Studio用の修正指示書」を出力。</li>



<li><strong>AI Studioで修正・完結（確実な実行）</strong>：指示書をAI Studioに流し込み、長文コードの整合性を保ったまま確実に修正を完了。</li>
</ul>
</li>
</ul>



<h2 class="wp-block-heading"><strong>まとめ</strong></h2>



<p class="wp-block-paragraph">さて、今回は、クラウド型生成AIについてその核心を３つのポイントにまとめたわけですが、こうやって記事を書いていても、まだなお、モヤモヤしているのは、3番目の、エラー処理のところです。Geminiに画像解析をさせてNotebookに引き継いでコードを抽出する、というところです。ここを一つにまとめたいのです。そこで、「画像解析からコード抽出」の部分を、ローカルLLMで処理することに挑戦してみたいと思います。その後で、コードが大規模の場合AI Studioへ引き継ぐのは、これはもう仕方ない事だと思います。だからハイブリッド型になりますね。</p>



<p class="wp-block-paragraph">ただし挑戦するにしても、私にとって生成AIを含めたデジタル関係の趣味に掛けられるお金は月3000円くらいまでです。YouTubeを見ていると、３社以上の生成AIを契約して月10万円以上かけているような、おそらく本職がデジタル関係の方がたくさんいらっしゃるわけですが、私は生活費の一部から出費するわけですので、身の丈に合ったサービスを利用することになります。</p>



<p class="wp-block-paragraph">改めて感じることですが、大企業から学ぶ真似ることは面白いと感じます。AIに聞けば、大企業がどのように諸課題を乗り越えているか解説してくれます。それを参考にして、それを小さくして簡単にして自分で作り込む。そのプロセスは結構未知な世界でワクワクするところです。そんなマインドが、個人開発を破綻させず、安全な長期利用につながっていくものと考えます。</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">29847</post-id>	</item>
		<item>
		<title>自作パペット（アバター）を作ってみました〜改良前〜脱Adobeを目指して！</title>
		<link>https://imakat.com/2026/03/12/28692/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Thu, 12 Mar 2026 02:19:50 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[Automator]]></category>
		<category><![CDATA[Gemini]]></category>
		<category><![CDATA[Adobe character animator]]></category>
		<category><![CDATA[パペット]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=28692</guid>

					<description><![CDATA[今回は、これからの動画作成で活躍してくれる**「新しく作った自作のパペット（アバター）」**について紹介したいと思います。これまで私の動画には、画面の左下に「Adobe Dr. Apple Smith」というキャラクター [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">今回は、これからの動画作成で活躍してくれる**「新しく作った自作のパペット（アバター）」**について紹介したいと思います。<br>これまで私の動画には、画面の左下に「Adobe Dr. Apple Smith」というキャラクターが頻繁に登場していました。顔の向きに合わせて首が動き、目や口もスムーズに動く非常に素晴らしいパペットだったのですが……実はそろそろ、彼から「卒業」をしたいと思います。</p>



<p class="wp-block-paragraph">動画をご覧ください。</p>


<div class="sc-dynamic-embed">
  <style>
  /* リンクの見た目を整える */
  .sc-dynamic-embed .sc-link-container { 
      display: flex; 
      margin-bottom: 10px; 
      flex-wrap: wrap; 
      align-items: center; 
  }
  .sc-dynamic-embed .sc-link { margin-bottom: 0; }
  .sc-dynamic-embed .sc-link a {
    font-size: 15px; 
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  @media (max-width: 500px) {
    .sc-dynamic-embed .sc-link a { font-size: 13px; }
  }

  .sc-dynamic-embed .imk-line {
      display: inline-block;
      width: 100%;
      border-radius: 2px;
      transition: background-color 0.1s;
  }

  .sc-dynamic-embed #subtitleOverlay,
  .sc-dynamic-embed #scSubtitleOverlay,
  .sc-dynamic-embed .overlay-cue,
  .sc-dynamic-embed .band {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
  }
  </style>

  <div class="sc-link-container">
    <p class="sc-link">
      <!-- ★環境依存排除：固定ドメインをルート相対パスへ置換完了 -->
      <a href="/ds62/?drid=74" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <!-- ★環境依存排除：[dynamic_external_html] にルート相対パスを指定し、functions.phpにURL動的解決を委ねる設計 -->
  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=sNA7JRyk.png" playsinline preload="none" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=uqGIUvdl.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=Ag8ayOZd.vtt" label="日本語" srclang="ja" kind="subtitles"></video></div><div class="dr5emd-sublist"><details translate="yes"><summary translate="yes">字幕一覧(クリック)</summary> <p translate="yes">
(<a href="#" class="imk-cue" data-seek="0:06" translate="no">00:00:06</a>)  それでは今回ですね、新しく作った自作のパペットを紹介していこうと思うんですけども<br>
(<a href="#" class="imk-cue" data-seek="0:16" translate="no">00:00:16</a>)  私今までですね、動画を作る時に頻繁に登場してたのが、この左端にいますですね<br>
(<a href="#" class="imk-cue" data-seek="0:27" translate="no">00:00:27</a>)  Adobe Dr. Apple SmithというAdobeのキャラクターです。パペットです。<br>
(<a href="#" class="imk-cue" data-seek="0:37" translate="no">00:00:37</a>)  で、これものすごく素晴らしいんですよね。顔の向きに応じて、首もゆっくり動きますし<br>
(<a href="#" class="imk-cue" data-seek="0:48" translate="no">00:00:48</a>)  口も目も非常にスムーズに動くという優れものなんですけども<br>
(<a href="#" class="imk-cue" data-seek="0:54" translate="no">00:00:54</a>)  ただ問題がありまして、それはこのAdobeのですね、サブスクに入らないと使えないんですよ。<br>
(<a href="#" class="imk-cue" data-seek="1:05" translate="no">00:01:05</a>)  これがですね、一番安い組み合わせでもってしても月1200円。<br>
(<a href="#" class="imk-cue" data-seek="1:15" translate="no">00:01:15</a>)  それはなかなか今のご時世、このキャラクター使うだけで<br>
(<a href="#" class="imk-cue" data-seek="1:23" translate="no">00:01:23</a>)  で、その他のAdobeのサービスというのはですね、画像加工したり色々面白みはあるんですけども<br>
(<a href="#" class="imk-cue" data-seek="1:33" translate="no">00:01:33</a>)  今や生成AIを使うとほとんど似たようなことができるんですね。<br>
(<a href="#" class="imk-cue" data-seek="1:41" translate="no">00:01:41</a>)  だからもう生成AIがあれば、メディアの加工もできるし、プログラム作成もできますしね。<br>
(<a href="#" class="imk-cue" data-seek="1:51" translate="no">00:01:51</a>)  色んなことが可能なんです。だからそれは非常にもったいない。<br>
(<a href="#" class="imk-cue" data-seek="1:58" translate="no">00:01:58</a>)  だからできればこのAdobeのサービスを停止して<br>
(<a href="#" class="imk-cue" data-seek="2:07" translate="no">00:02:07</a>)  もう自前で作ったこのパペットですね。Adobeと比べれば見劣りするんですけどもね。<br>
(<a href="#" class="imk-cue" data-seek="2:16" translate="no">00:02:16</a>)  まあそれでもこのように目も動きますし、口も動くしで、首も多少動く。<br>
(<a href="#" class="imk-cue" data-seek="2:23" translate="no">00:02:23</a>)  まあそんな形でですね、使い物にはなんとかなってるかなと思うんですよ。ここは割り切りですね。<br>
(<a href="#" class="imk-cue" data-seek="2:32" translate="no">00:02:32</a>)  ええまあ、この自前のパペットでですね、これからやっていこうと思ってます。<br>
(<a href="#" class="imk-cue" data-seek="2:39" translate="no">00:02:39</a>)  ええと、それではですね、今回作ったお手製のパペットですね、を紹介していきたいと思います。<br>
(<a href="#" class="imk-cue" data-seek="2:49" translate="no">00:02:49</a>)  まだ名前はないんですが、まあimakatブログで使っていこうと思うキャラクターですね。<br>
(<a href="#" class="imk-cue" data-seek="2:59" translate="no">00:02:59</a>)  いまかっちゃん、変だね。なんだろうね。なんかいい名前があるといいんですけどね。<br>
(<a href="#" class="imk-cue" data-seek="3:11" translate="no">00:03:11</a>)  まあ、とにかくですね、今から紹介していきたいと思います。<br>
(<a href="#" class="imk-cue" data-seek="3:16" translate="no">00:03:16</a>)  で、基本的には作るのはですね、Google Geminiですね。<br>
(<a href="#" class="imk-cue" data-seek="3:25" translate="no">00:03:25</a>)  Google Geminiを使ってですね、Geminiにプログラムを書いてもらうと。<br>
(<a href="#" class="imk-cue" data-seek="3:34" translate="no">00:03:34</a>)  いうことをして進めます。これが非常に賢いんでね。<br>
(<a href="#" class="imk-cue" data-seek="3:41" translate="no">00:03:41</a>)  こちらがその日本語で質問していけば、どんどん作ってくれるという代物でございます。<br>
(<a href="#" class="imk-cue" data-seek="3:49" translate="no">00:03:49</a>)  で、それに従ってですね、あのMacの中にフォルダを用意します。<br>
(<a href="#" class="imk-cue" data-seek="3:58" translate="no">00:03:58</a>)  フォルダとファイルを用意するということが必要になります。<br>
(<a href="#" class="imk-cue" data-seek="4:03" translate="no">00:04:03</a>)  mypuppet_systemっていうのを作ってですね、その中にavatar_module<br>
(<a href="#" class="imk-cue" data-seek="4:13" translate="no">00:04:13</a>)  その中にrun_puppet.py、これが動かすためのPythonプログラムです。<br>
(<a href="#" class="imk-cue" data-seek="4:20" translate="no">00:04:20</a>)  で、assets、これが動かす対象となる画像ですね、それが入ってます。<br>
(<a href="#" class="imk-cue" data-seek="4:30" translate="no">00:04:30</a>)  あとconfigのjsonが入ってます。assetsを開くと<br>
(<a href="#" class="imk-cue" data-seek="4:37" translate="no">00:04:37</a>)  目の動き用、口の動き用、体ですね、それとあと頭。<br>
(<a href="#" class="imk-cue" data-seek="4:49" translate="no">00:04:49</a>)  そういう形でですね、パーツごとに分けて作っていきます。<br>
(<a href="#" class="imk-cue" data-seek="4:55" translate="no">00:04:55</a>)  例えば目一つ見てみましょうか。ちょっと小さいですけどもね。<br>
(<a href="#" class="imk-cue" data-seek="5:02" translate="no">00:05:02</a>)  これはeye_up.png、上目遣いの目だけです。<br>
(<a href="#" class="imk-cue" data-seek="5:13" translate="no">00:05:13</a>)  こういうふうに作りますね。で、作ってもらったプログラムをですね、run_puppet.py<br>
(<a href="#" class="imk-cue" data-seek="5:22" translate="no">00:05:22</a>)  先ほどもちょっと出てきましたけども、そういう形で書き込みます。<br>
(<a href="#" class="imk-cue" data-seek="5:29" translate="no">00:05:29</a>)  で、それをですね、ターミナルですね、それをターミナルで実行するという形をとってます。<br>
(<a href="#" class="imk-cue" data-seek="5:43" translate="no">00:05:43</a>)  なかなか素晴らしい出来でして、ちょっと頭の動きが<br>
(<a href="#" class="imk-cue" data-seek="5:49" translate="no">00:05:49</a>)  少し動いたり動かなかったりってこともあるんですが、まあ大体問題なく動いてくれてると。<br>
(<a href="#" class="imk-cue" data-seek="5:59" translate="no">00:05:59</a>)  少し動き出すと、少し不安定な動きになるっていうのが今の課題です。<br>
(<a href="#" class="imk-cue" data-seek="6:07" translate="no">00:06:07</a>)  ええ、そんなところでですね、作り上げたパペットです。<br>
(<a href="#" class="imk-cue" data-seek="6:12" translate="no">00:06:12</a>)  まあいろんな形で使っていこうと思っております。<br>
(<a href="#" class="imk-cue" data-seek="6:18" translate="no">00:06:18</a>)  ええと、それではですね、まあ次にこのさっき作ったパペットですけれども<br>
(<a href="#" class="imk-cue" data-seek="6:29" translate="no">00:06:29</a>)  まあ実際に今このように動いてますが、これあのターミナルから起動するというのは<br>
(<a href="#" class="imk-cue" data-seek="6:38" translate="no">00:06:38</a>)  結構慣れないと面倒くさい話なんで、ちょっとやってみますとね。<br>
(<a href="#" class="imk-cue" data-seek="6:46" translate="no">00:06:46</a>)  こういうコマンドをですね、打ち込むんです。で、立ち上げると。<br>
(<a href="#" class="imk-cue" data-seek="6:56" translate="no">00:06:56</a>)  まあこんなような形で立ち上がって、それを使うという形になるわけですね。<br>
(<a href="#" class="imk-cue" data-seek="7:05" translate="no">00:07:05</a>)  これ今私が話してる声で連動してます。<br>
(<a href="#" class="imk-cue" data-seek="7:13" translate="no">00:07:13</a>)  まあところがこれは非常に難しい、厄介なんでですね、これは使いたくないわけですよ、みんな。<br>
(<a href="#" class="imk-cue" data-seek="7:22" translate="no">00:07:22</a>)  で、どういう方法をとるかというと、AppleのAutomatorというものを使ってですね<br>
(<a href="#" class="imk-cue" data-seek="7:30" translate="no">00:07:30</a>)  まあ簡単なプログラムを書き込むというふうなですね、作業をします。<br>
(<a href="#" class="imk-cue" data-seek="7:40" translate="no">00:07:40</a>)  こういうものですね。MacのAutomatorを立ち上げてですね<br>
(<a href="#" class="imk-cue" data-seek="7:48" translate="no">00:07:48</a>)  で、そこでシェルスクリプトを実行ってものを選択して、ここに収めます。<br>
(<a href="#" class="imk-cue" data-seek="7:57" translate="no">00:07:57</a>)  で、それでとっても短いプログラムですけども、こういうプログラムを書きます。<br>
(<a href="#" class="imk-cue" data-seek="8:05" translate="no">00:08:05</a>)  実はこれさっきですね、ターミナルに打ち込んだコマンドと全く同じなんですね。<br>
(<a href="#" class="imk-cue" data-seek="8:13" translate="no">00:08:13</a>)  それをここに書き込んで、アプリケーションとして登録するということをやります。<br>
(<a href="#" class="imk-cue" data-seek="8:23" translate="no">00:08:23</a>)  そうしますと、まあこういう、自作パペット起動.app、ってものができます。<br>
(<a href="#" class="imk-cue" data-seek="8:30" translate="no">00:08:30</a>)  で、この状態でですね、これをクリックします。<br>
(<a href="#" class="imk-cue" data-seek="8:37" translate="no">00:08:37</a>)  そうすると、実はここから立ち上がることができます。<br>
(<a href="#" class="imk-cue" data-seek="8:48" translate="no">00:08:48</a>)  この、自作パペット起動.app、をクリックして立ち上がった画面がこれになります。<br>
(<a href="#" class="imk-cue" data-seek="8:56" translate="no">00:08:56</a>)  このような方法でですね、アプリ化して起動させるというのが非常に楽な使い方になります。<br>
(<a href="#" class="imk-cue" data-seek="9:05" translate="no">00:09:05</a>)  以上、補足でした。<br>
</p> </details>
<style>
details { font: 16px "Open Sans", Calibri, sans-serif; width: 100%; }
details > summary { padding: 2px 6px; width: 100%; background-color: #ddd; border: none; box-shadow: 3px 3px 4px black; cursor: pointer; list-style: none; }
details > p { font: 14px "Open Sans", Calibri, sans-serif; height:150px; overflow: scroll; background-color: #EDF7FF; padding: 2px 6px; margin: 0; box-shadow: 3px 3px 4px black; }
</style>
</div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

  <script>
  (function(){
    var me = document.currentScript;
    var wrapper = me ? me.closest('.sc-dynamic-embed') : null;

    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video) return false; 
      
      if (video.dataset.subInit === 'true') return true; 
      video.dataset.subInit = 'true';

      var oldOverlay = target.querySelector('#subtitleOverlay') || target.querySelector('#scSubtitleOverlay');
      if (oldOverlay) {
          oldOverlay.style.setProperty('display', 'none', 'important');
          oldOverlay.innerHTML = ''; 
      }

      // 全画面・PiP・iOS全画面の判定（dr52.php準拠＋Safari presentationMode完全対応）
      function isSpecialMode() {
        var fsEl = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
        var isFs = !!fsEl;
        var isWebkitFs = (video.webkitPresentationMode === "fullscreen") || !!video.webkitDisplayingFullscreen;
        var isPiP = !!(document.pictureInPictureElement && document.pictureInPictureElement === video) || (video.webkitPresentationMode === "picture-in-picture");
        return isFs || isWebkitFs || isPiP;
      }

      // 字幕トラックの表示/非表示を更新
      function updateTrackMode() {
        var hasList = (listContainer !== null);
        var desiredMode = (isSpecialMode() || !hasList) ? "showing" : "hidden";
        try {
          if (video.textTracks && video.textTracks.length > 0) {
            for (var i = 0; i < video.textTracks.length; i++) {
              var track = video.textTracks[i];
              if ((track.kind === 'subtitles' || track.kind === 'captions') && track.mode !== desiredMode) {
                track.mode = desiredMode;
              }
            }
          }
        } catch(e) {}
      }

      // 初回の反映
      updateTrackMode();

      // 各種全画面・PiP切り替えイベントの即時検知リスナーを登録（video本体・document双方を監視）
      ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange'].forEach(function(evtName) {
        document.addEventListener(evtName, updateTrackMode, false);
        video.addEventListener(evtName, updateTrackMode, false);
      });
      video.addEventListener('webkitbeginfullscreen', updateTrackMode, false);
      video.addEventListener('webkitendfullscreen', updateTrackMode, false);
      video.addEventListener('webkitpresentationmodechanged', updateTrackMode, false);
      video.addEventListener('enterpictureinpicture', updateTrackMode, false);
      video.addEventListener('leavepictureinpicture', updateTrackMode, false);
      video.addEventListener('play', updateTrackMode, false);
      video.addEventListener('pause', updateTrackMode, false);

      // 字幕一覧が存在する場合のみ、リストのフォーマット処理を行う
      if (listContainer) {
          var detailsEl = target.querySelector("details");
          if (detailsEl) {
              detailsEl.open = true; 
              var summaryEl = detailsEl.querySelector("summary");
              if (summaryEl) summaryEl.textContent = "字幕(シーン)はここをクリック";
          }

          if (!listContainer.dataset.formatted) {
              var html = listContainer.innerHTML;
              var lines = html.split(/<br\s*\/?>/i);
              var newHtml = "";
              for(var j=0; j<lines.length; j++) {
                  if(lines[j].trim() === "") continue;
                  newHtml += "<span class='imk-line'>" + lines[j] + "</span><br>";
              }
              listContainer.innerHTML = newHtml;
              listContainer.dataset.formatted = "true";
          }

          var rootSublist = target.querySelector(".dr5-sublist") || listContainer.parentElement;
          if (rootSublist) {
            rootSublist.addEventListener("click", function(e){
              var a = e.target.closest && e.target.closest("a.imk-cue[data-seek]");
              if(!a) return;
              e.preventDefault();
              var ts = a.getAttribute("data-seek");
              if(!ts) return;
              var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
              var sec = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2]: null);
              if(sec==null) return;
              try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
            });
          }
      }

      // 再生中（時間進行時）の追従とハイライト更新
      video.addEventListener("timeupdate", function(){
        updateTrackMode();

        var hasList = (listContainer !== null);
        if (!hasList) return;

        var cues = listContainer.querySelectorAll("a.imk-cue");
        if(cues.length === 0) return;
        var cur = video.currentTime;
        var activeA = null;

        for(var i=0; i<cues.length; i++){
            var ts = cues[i].getAttribute("data-seek");
            if(!ts) continue;
            var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
            var t = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

        if(activeA){
            var activeLine = activeA.closest(".imk-line");
            if(!activeLine) activeLine = activeA;

            if(activeLine.classList.contains("active-hl")) return;

            var allLines = listContainer.querySelectorAll(".imk-line");
            for(var k=0; k<allLines.length; k++) {
                allLines[k].classList.remove("active-hl");
                allLines[k].removeAttribute("style"); 
            }
            var allLinks = listContainer.querySelectorAll("a");
            for(var m=0; m<allLinks.length; m++) {
                allLinks[m].classList.remove("active-hl");
                allLinks[m].removeAttribute("style"); 
            }

            activeLine.classList.add("active-hl");
            activeLine.style.setProperty("background-color", "#ffff00", "important");
            activeLine.style.setProperty("color", "red", "important");
            activeLine.style.setProperty("font-weight", "normal", "important");
            
            var newLinks = activeLine.querySelectorAll("a");
            for(var n=0; n<newLinks.length; n++) {
                newLinks[n].style.setProperty("color", "red", "important");
                newLinks[n].style.setProperty("text-decoration", "none", "important");
            }

            if(listContainer.offsetParent !== null){
                var containerRect = listContainer.getBoundingClientRect();
                var activeRect = activeLine.getBoundingClientRect();
                var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (activeLine.clientHeight / 2);
                listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
            }
        }
      });

      return true;
    }

    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    if (!window.scStopAndGo) {
      window.scStopAndGo = function(event, link){
        try{
          var mediaEls = document.querySelectorAll('video, audio');
          mediaEls.forEach(function(m){
            try{
              if (!m.paused) m.pause();
              if (document.pictureInPictureElement === m && document.exitPictureInPicture) {
                document.exitPictureInPicture().catch(function(){});
              }
            }catch(e){}
          });
        }finally{
          event.preventDefault();
          setTimeout(function(){
            if (link.target === '_blank') {
              window.open(link.href, '_blank');
            } else {
              window.location.href = link.href;
            }
          }, 50);
        }
        return false;
      };
    }
  })();
  </script>
</div>



<div class="wp-block-cocoon-blocks-toggle-box-1 toggle-wrap toggle-box block-box not-nested-style cocoon-block-toggle"><input id="toggle-checkbox-202604180750240" class="toggle-checkbox" type="checkbox"/><label class="toggle-button" for="toggle-checkbox-202604180750240"><strong><span class="marker">コードと要約</span><span class="marker">(クリック)</span></strong></label><div class="toggle-content">
<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>自作パペット_py.pub.txt<br>要約：<br>このシステムは、顔認識と音声入力を利用してリアルタイムで動作するデスクトップパペットを実現します。<br><code>run_ui.py</code>は、パペットの各種設定を行うGUIアプリケーションです。キャラクターの新規作成、複製、選択、そしてボリューム閾値、グローバルスケール、顔の傾き制限、目の感度、カメラ/マイクIDといったパラメータ調整機能を提供します。これらの設定はキャラクターごとにJSONファイルとして保存されます。<br><code>run_puppet.py</code>は、UIで選択・設定されたキャラクターとパラメータに基づき、実際のパペット動作を制御するスクリプトです。OpenCVとMediaPipe Face Meshを用いてカメラ映像から顔の傾き、目の動き、口の形を検出し、マイクからの音声ボリュームと連携させてアバターの頭の回転、視線、口の動きをリアルタイムで再現します。キャリブレーションデータもキャラクターごとに保存されます。<br>Automatorスクリプトは、これらのPythonスクリプトの実行を補助します。「自作パペット起動.app」は設定UIを立ち上げ、「パペット書き出し起動.app」はPixelmator Proで開いているドキュメントの各レイヤーをPNG画像として書き出し、キャラクターごとの設定JSONを自動生成した後、該当するパペットを起動する一連の処理を行います。これにより、Pixelmator Proでの画像編集からパペット起動までがスムーズに連携されます。</td></tr><tr><td><a href="https://imakat.com/script_list/?pubtxt=自作パペット_py_pub.txt" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=zrU95MiY.png" alt="" style="width:120px; height:auto;"></a></td></tr><tr><td>公開スクリプトに関するお問い合わせは以下へ↓</td></tr><tr><td><a rel="noopener" target="_blank" href="https://gemini.google.com/gem/1Dp-NLSA5j5OXE3B1Ki2IaBRCvq4CGa6t?usp=sharing"><img decoding="async" src="https://imakat.com/rd.php?id=s7BMZHhB.png" alt="" style="width:120px; height:auto;"></a></td></tr></tbody></table></figure>
</div></div>



<h4 class="wp-block-heading"><strong>なぜパペットを自作しようと思ったのか？</strong></h4>



<p class="wp-block-paragraph">最大の理由は**「コスト」**です。<br>Adobeの素晴らしいパペットを使うためには、当然ながらAdobeのサブスクリプションに加入する必要があります。一番安いプランの組み合わせでも、月額1,200円ほどかかってしまいます。<br>「このキャラクターを使うためだけに、毎月課金し続けるのはどうなんだろう？」と悩んでいました。今は生成AI（画像生成AIやテキスト生成AI）がこれだけ発達し、メディアの加工やプログラムの作成まで何でもできる時代です。「それなら、AIの力を借りて自分で作ってしまおう！」と思い立ったのがきっかけです。</p>



<h4 class="wp-block-heading"><strong>新キャラクター「いまかっちゃん（仮）？」</strong></h4>



<p class="wp-block-paragraph">というわけで、完全自前で作り上げたのがこちらのパペットです。（※名前は暫定で「いまかっちゃん」と思いつきましたが、ちょっと変な感じもしています。）<br>Adobeのパペットと比べてしまうと多少見劣りする部分はありますが、動画用としては十分な機能を持っています。<br><strong>音声連動：</strong> 私が話す声に連動して口がパクパクと動きます。<br><strong>目の動き：</strong> 上目遣いなど、視線も動きます。<br><strong>首の動き：</strong> 多少ですが顔の向きも変わります。（※現状、少し不安定な動きになることがあり、今後の課題です）<br>動画を作る上での「使い物」にはなんとか仕上がったかなと、個人的には割り切って満足しています。</p>



<h4 class="wp-block-heading"><strong>Google Geminiに丸投げ！？</strong></h4>



<p class="wp-block-paragraph">「どうやって作ったの？」と疑問に思うかもしれませんが、実はプログラミングの大部分は**AI（Google Gemini）**にお願いしました。<br><strong>Geminiに質問する：</strong> 日本語で「こういう動きをするプログラムを書いて」と質問し、Pythonのコードを書いてもらいます。Geminiは非常に賢く、どんどんコードを生成してくれました。<br><strong>パーツ画像の用意：</strong> 目（上・下・右・左）、口（開・閉）、体、頭など、パーツごとに細かく分けた画像（PNG形式）を用意します。<br><strong>フォルダ構成：</strong> Macの中に専用フォルダ（mypuppet_systemなど）を作り、Pythonの実行ファイル（run_puppet.py）と、先ほどの画像パーツ群（assetsフォルダ）を格納して連動させました。</p>



<h4 class="wp-block-heading"><strong>Mac「Automator」で起動を劇的にラクにする方法</strong></h4>



<p class="wp-block-paragraph">自作プログラムの弱点として、「毎回ターミナル（黒い画面）を開いてコマンドを打ち込まないと起動しない」という厄介な問題がありました。これでは面倒ですよね。<br>そこで、Mac標準アプリの**「Automator」**を使って、ワンクリックで起動できるように一工夫しました。<br><strong>手順：</strong> Automatorを立ち上げ、「シェルスクリプトを実行」を選択。そこにターミナルで打ち込んでいた短いコマンドをコピペするだけ。<br><strong>アプリ化：</strong> これをアプリケーションとして保存すれば、**「自作パペット起動.app」**の完成です！<br>これからは、このアプリアイコンをダブルクリックするだけで、サクッとパペットを呼び出せるようになりました。</p>



<h4 class="wp-block-heading">OBSへのパペット設定</h4>



<p class="wp-block-paragraph">OBSへのパペットの組み込みですが、OBSのソース→ウインドウキャプチャ、この中から、パペットのあるウインドウを選択します。</p>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=PeocProJ.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=PeocProJ.png" alt=""/></a></figure>



<p class="wp-block-paragraph">STREAM DECKがあると便利です。マルチアクションにて、OBS.app→自作パペット起動.app、と設定すればラクです。</p>



<h4 class="wp-block-heading">さてと。。</h4>



<p class="wp-block-paragraph">その後の改善として、Pixelmator Proとの連携を作っています。形になったら紹介します。<br>生成AIを活用すれば、プログラミングの深い知識がなくても、日常の「ちょっと不便」「コストを削りたい」を解決できるツールが作れてしまいますよね。便利な時代になりました。<br><br></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">28692</post-id>	</item>
		<item>
		<title>【Gem活用】第１弾、コード(スクリプト)作成のエコシステムを作ってみた</title>
		<link>https://imakat.com/2026/02/16/28530/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Mon, 16 Feb 2026 05:11:51 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[スクリプト]]></category>
		<category><![CDATA[Gemini]]></category>
		<category><![CDATA[エコシステム]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=28530</guid>

					<description><![CDATA[26.10.03:Gemは廃止されその機能がSkillsに移行されると発表がありました。本記事のコード作成機能はNotebookへ移行済みです。(ID-29269 ID-29358) はじめに コード作成って何？なんとも [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">26.10.03:Gemは廃止されその機能がSkillsに移行されると発表がありました。本記事のコード作成機能はNotebookへ移行済みです。(<a href="https://imakat.com/2026/06/18/29269/" target="_blank">ID-29269</a> <a href="https://imakat.com/2026/06/29/29358/" target="_blank">ID-29358</a>)</p>



<h3 class="wp-block-heading">はじめに</h3>



<p class="wp-block-paragraph">コード作成って何？なんとも刺さりの悪い言葉なのですが、昔からある言い方に直せば、「コンピュータプログラム」のことです。これが長ったらしいので、コードと呼んでいます。英単語ではcodeです。音楽で使う和音を意味するコードはchordですね。綴りが違います。能書はこのくらいにして中身に入ります。</p>


<div class="sc-dynamic-embed">
  <style>
  /* リンクの見た目を整える */
  .sc-dynamic-embed .sc-link-container { 
      display: flex; 
      margin-bottom: 10px; 
      flex-wrap: wrap; 
      align-items: center; 
  }
  .sc-dynamic-embed .sc-link { margin-bottom: 0; }
  .sc-dynamic-embed .sc-link a {
    font-size: 15px; 
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  @media (max-width: 500px) {
    .sc-dynamic-embed .sc-link a { font-size: 13px; }
  }

  .sc-dynamic-embed .imk-line {
      display: inline-block;
      width: 100%;
      border-radius: 2px;
      transition: background-color 0.1s;
  }

  .sc-dynamic-embed #subtitleOverlay,
  .sc-dynamic-embed #scSubtitleOverlay,
  .sc-dynamic-embed .overlay-cue,
  .sc-dynamic-embed .band {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
  }
  </style>

  <div class="sc-link-container">
    <p class="sc-link">
      <!-- ★環境依存排除：固定ドメインをルート相対パスへ置換完了 -->
      <a href="/ds62/?drid=72" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <!-- ★環境依存排除：[dynamic_external_html] にルート相対パスを指定し、functions.phpにURL動的解決を委ねる設計 -->
  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=b8zFYGBF.png" playsinline preload="none" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=zneKyTGw.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=EQDj6mHk.vtt" label="日本語" srclang="ja" kind="subtitles"></video></div><div class="dr5emd-sublist"><details translate="yes"><summary translate="yes">字幕一覧(クリック)</summary> <p translate="yes">
(<a href="#" class="imk-cue" data-seek="0:00" translate="no">00:00:00</a>) コード作成のエコシステムの紹介<br>
(<a href="#" class="imk-cue" data-seek="0:06" translate="no">00:00:06</a>) 今日のテーマはコード作成のエコシステムということについてお話ししようと思います。<br>
(<a href="#" class="imk-cue" data-seek="0:15" translate="no">00:00:15</a>) 私のプログラムコードの作成作業はGeminiとの対話で始まります。<br>
(<a href="#" class="imk-cue" data-seek="0:24" translate="no">00:00:24</a>) 以前はChatGPTでしたけども、最近Geminiに変えました。<br>
(<a href="#" class="imk-cue" data-seek="0:31" translate="no">00:00:31</a>) その理由はブログをお読みください。<br>
(<a href="#" class="imk-cue" data-seek="0:36" translate="no">00:00:36</a>) 使い方ですけども、まずは実現したいアイデアをそのままAIに投げかけてみます。<br>
(<a href="#" class="imk-cue" data-seek="0:48" translate="no">00:00:48</a>) そこからQ&Aを重ね、ロジックを固めていき、コードの作成を行います。<br>
(<a href="#" class="imk-cue" data-seek="0:56" translate="no">00:00:56</a>) AIをパートナーに据えることで、まずは動く形を迅速に作り上げることが<br>
(<a href="#" class="imk-cue" data-seek="1:05" translate="no">00:01:05</a>) できるのが大きなメリットです。<br>
(<a href="#" class="imk-cue" data-seek="1:10" translate="no">00:01:10</a>) しかし、完成したコードをただ置いておくだけではもったいないです。再活用したいです。<br>
(<a href="#" class="imk-cue" data-seek="1:19" translate="no">00:01:19</a>) そこで後で見返したときに、何のためのプログラムかを一目でわかるように、<br>
(<a href="#" class="imk-cue" data-seek="1:28" translate="no">00:01:28</a>) Geminiに日本語の要約を作成させます。<br>
(<a href="#" class="imk-cue" data-seek="1:32" translate="no">00:01:32</a>) その要約とコードを一緒にしてテキストファイルへ書き込み、それをITスクリプト管理フォルダ、<br>
(<a href="#" class="imk-cue" data-seek="1:48" translate="no">00:01:48</a>) ここへですね、収めます。<br>
(<a href="#" class="imk-cue" data-seek="1:51" translate="no">00:01:51</a>) その次のステップとして重要になるのがセキュリティ対策です。<br>
(<a href="#" class="imk-cue" data-seek="1:57" translate="no">00:01:57</a>) 個人情報や認証キーがコードに書き込まれていますので、これを隠すようにします。<br>
(<a href="#" class="imk-cue" data-seek="2:08" translate="no">00:02:08</a>) ルールを作って、例えばXXXXXなどの別の文字列へ機械的に置き換えます。<br>
(<a href="#" class="imk-cue" data-seek="2:22" translate="no">00:02:22</a>) 置き換えた後で、それらのプログラムをscripts_pubフォルダへ収めます。<br>
(<a href="#" class="imk-cue" data-seek="2:31" translate="no">00:02:31</a>) これを誰でも使える公開資料にします。<br>
(<a href="#" class="imk-cue" data-seek="2:36" translate="no">00:02:36</a>) このscripts_pubフォルダですが、2つのルートで活用します。<br>
(<a href="#" class="imk-cue" data-seek="2:44" translate="no">00:02:44</a>) 1つは私のブログです。公開スクリプト一覧として整理して、<br>
(<a href="#" class="imk-cue" data-seek="2:56" translate="no">00:02:56</a>) ユーザーに自由に使ってもらう資料として開放しています。<br>
(<a href="#" class="imk-cue" data-seek="3:03" translate="no">00:03:03</a>) そしてもう1つですが、これらのスクリプトを知識ソースとして、<br>
(<a href="#" class="imk-cue" data-seek="3:10" translate="no">00:03:10</a>) 私専用のGemを構築しています。<br>
(<a href="#" class="imk-cue" data-seek="3:14" translate="no">00:03:14</a>) これはユーザーへのサポート窓口になると同時に、<br>
(<a href="#" class="imk-cue" data-seek="3:20" translate="no">00:03:20</a>) 私自身が次のコードを生成するための最強のデータベースになるものです。<br>
(<a href="#" class="imk-cue" data-seek="3:29" translate="no">00:03:29</a>) その後運用していくと、不具合の修復だとか改善の必要性に迫られるわけですが、<br>
(<a href="#" class="imk-cue" data-seek="3:38" translate="no">00:03:38</a>) 現状のコードはすでに知識ソースとして埋め込まれているので、<br>
(<a href="#" class="imk-cue" data-seek="3:45" translate="no">00:03:45</a>) 特段の準備をすることもなく速やかにそれらの開発に着手できるわけです。<br>
(<a href="#" class="imk-cue" data-seek="3:54" translate="no">00:03:54</a>) 回せば回すほどAIは私の意図を学習して、システムの精度は増していくと。<br>
(<a href="#" class="imk-cue" data-seek="4:02" translate="no">00:04:02</a>) 進化のループと言えます。<br>
(<a href="#" class="imk-cue" data-seek="4:06" translate="no">00:04:06</a>) 今回はプログラム作成を例に挙げましたけども、この情報の整理、変換、再学習という循環は、<br>
(<a href="#" class="imk-cue" data-seek="4:18" translate="no">00:04:18</a>) 文章作成、研究、趣味の記録など、あらゆる分野に応用が可能だと思います。<br>
(<a href="#" class="imk-cue" data-seek="4:26" translate="no">00:04:26</a>) 皆さんのライフワークにこのエコシステムを取り入れたら、どのような変化が起きるでしょうか。<br>
(<a href="#" class="imk-cue" data-seek="4:34" translate="no">00:04:34</a>) 私は高齢者ではありますけども、高齢者に役立つようなうまい使い方もできそうな気がしています。<br>
(<a href="#" class="imk-cue" data-seek="4:43" translate="no">00:04:43</a>) 以上です。<br>
</p> </details>
<style>
details { font: 16px "Open Sans", Calibri, sans-serif; width: 100%; }
details > summary { padding: 2px 6px; width: 100%; background-color: #ddd; border: none; box-shadow: 3px 3px 4px black; cursor: pointer; list-style: none; }
details > p { font: 14px "Open Sans", Calibri, sans-serif; height:150px; overflow: scroll; background-color: #EDF7FF; padding: 2px 6px; margin: 0; box-shadow: 3px 3px 4px black; }
</style>
</div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

  <script>
  (function(){
    var me = document.currentScript;
    var wrapper = me ? me.closest('.sc-dynamic-embed') : null;

    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video) return false; 
      
      if (video.dataset.subInit === 'true') return true; 
      video.dataset.subInit = 'true';

      var oldOverlay = target.querySelector('#subtitleOverlay') || target.querySelector('#scSubtitleOverlay');
      if (oldOverlay) {
          oldOverlay.style.setProperty('display', 'none', 'important');
          oldOverlay.innerHTML = ''; 
      }

      // 全画面・PiP・iOS全画面の判定（dr52.php準拠＋Safari presentationMode完全対応）
      function isSpecialMode() {
        var fsEl = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
        var isFs = !!fsEl;
        var isWebkitFs = (video.webkitPresentationMode === "fullscreen") || !!video.webkitDisplayingFullscreen;
        var isPiP = !!(document.pictureInPictureElement && document.pictureInPictureElement === video) || (video.webkitPresentationMode === "picture-in-picture");
        return isFs || isWebkitFs || isPiP;
      }

      // 字幕トラックの表示/非表示を更新
      function updateTrackMode() {
        var hasList = (listContainer !== null);
        var desiredMode = (isSpecialMode() || !hasList) ? "showing" : "hidden";
        try {
          if (video.textTracks && video.textTracks.length > 0) {
            for (var i = 0; i < video.textTracks.length; i++) {
              var track = video.textTracks[i];
              if ((track.kind === 'subtitles' || track.kind === 'captions') && track.mode !== desiredMode) {
                track.mode = desiredMode;
              }
            }
          }
        } catch(e) {}
      }

      // 初回の反映
      updateTrackMode();

      // 各種全画面・PiP切り替えイベントの即時検知リスナーを登録（video本体・document双方を監視）
      ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange'].forEach(function(evtName) {
        document.addEventListener(evtName, updateTrackMode, false);
        video.addEventListener(evtName, updateTrackMode, false);
      });
      video.addEventListener('webkitbeginfullscreen', updateTrackMode, false);
      video.addEventListener('webkitendfullscreen', updateTrackMode, false);
      video.addEventListener('webkitpresentationmodechanged', updateTrackMode, false);
      video.addEventListener('enterpictureinpicture', updateTrackMode, false);
      video.addEventListener('leavepictureinpicture', updateTrackMode, false);
      video.addEventListener('play', updateTrackMode, false);
      video.addEventListener('pause', updateTrackMode, false);

      // 字幕一覧が存在する場合のみ、リストのフォーマット処理を行う
      if (listContainer) {
          var detailsEl = target.querySelector("details");
          if (detailsEl) {
              detailsEl.open = true; 
              var summaryEl = detailsEl.querySelector("summary");
              if (summaryEl) summaryEl.textContent = "字幕(シーン)はここをクリック";
          }

          if (!listContainer.dataset.formatted) {
              var html = listContainer.innerHTML;
              var lines = html.split(/<br\s*\/?>/i);
              var newHtml = "";
              for(var j=0; j<lines.length; j++) {
                  if(lines[j].trim() === "") continue;
                  newHtml += "<span class='imk-line'>" + lines[j] + "</span><br>";
              }
              listContainer.innerHTML = newHtml;
              listContainer.dataset.formatted = "true";
          }

          var rootSublist = target.querySelector(".dr5-sublist") || listContainer.parentElement;
          if (rootSublist) {
            rootSublist.addEventListener("click", function(e){
              var a = e.target.closest && e.target.closest("a.imk-cue[data-seek]");
              if(!a) return;
              e.preventDefault();
              var ts = a.getAttribute("data-seek");
              if(!ts) return;
              var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
              var sec = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2]: null);
              if(sec==null) return;
              try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
            });
          }
      }

      // 再生中（時間進行時）の追従とハイライト更新
      video.addEventListener("timeupdate", function(){
        updateTrackMode();

        var hasList = (listContainer !== null);
        if (!hasList) return;

        var cues = listContainer.querySelectorAll("a.imk-cue");
        if(cues.length === 0) return;
        var cur = video.currentTime;
        var activeA = null;

        for(var i=0; i<cues.length; i++){
            var ts = cues[i].getAttribute("data-seek");
            if(!ts) continue;
            var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
            var t = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

        if(activeA){
            var activeLine = activeA.closest(".imk-line");
            if(!activeLine) activeLine = activeA;

            if(activeLine.classList.contains("active-hl")) return;

            var allLines = listContainer.querySelectorAll(".imk-line");
            for(var k=0; k<allLines.length; k++) {
                allLines[k].classList.remove("active-hl");
                allLines[k].removeAttribute("style"); 
            }
            var allLinks = listContainer.querySelectorAll("a");
            for(var m=0; m<allLinks.length; m++) {
                allLinks[m].classList.remove("active-hl");
                allLinks[m].removeAttribute("style"); 
            }

            activeLine.classList.add("active-hl");
            activeLine.style.setProperty("background-color", "#ffff00", "important");
            activeLine.style.setProperty("color", "red", "important");
            activeLine.style.setProperty("font-weight", "normal", "important");
            
            var newLinks = activeLine.querySelectorAll("a");
            for(var n=0; n<newLinks.length; n++) {
                newLinks[n].style.setProperty("color", "red", "important");
                newLinks[n].style.setProperty("text-decoration", "none", "important");
            }

            if(listContainer.offsetParent !== null){
                var containerRect = listContainer.getBoundingClientRect();
                var activeRect = activeLine.getBoundingClientRect();
                var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (activeLine.clientHeight / 2);
                listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
            }
        }
      });

      return true;
    }

    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    if (!window.scStopAndGo) {
      window.scStopAndGo = function(event, link){
        try{
          var mediaEls = document.querySelectorAll('video, audio');
          mediaEls.forEach(function(m){
            try{
              if (!m.paused) m.pause();
              if (document.pictureInPictureElement === m && document.exitPictureInPicture) {
                document.exitPictureInPicture().catch(function(){});
              }
            }catch(e){}
          });
        }finally{
          event.preventDefault();
          setTimeout(function(){
            if (link.target === '_blank') {
              window.open(link.href, '_blank');
            } else {
              window.location.href = link.href;
            }
          }, 50);
        }
        return false;
      };
    }
  })();
  </script>
</div>



<a rel="noopener" target="_blank" href="https://docs.google.com/drawings/d/1_65TflS4kAJ6xf7RoGl22oAYRljreVTvBjsnmbcZQQ8/edit?usp=sharing" 
>
<img decoding="async" src="https://docs.google.com/drawings/d/e/2PACX-1vQW9KCkzFbj3Zaa4sZPLjInUUHwKJ2FdpFW388svQ82AkWComAKJSEDe5VbT8z1w0uqnoSeq00BuiUf/pub?w=1920&#038;h=1440"
></a>



<div class="wp-block-cocoon-blocks-toggle-box-1 toggle-wrap toggle-box block-box not-nested-style cocoon-block-toggle"><input id="toggle-checkbox-202610030845080" class="toggle-checkbox" type="checkbox"/><label class="toggle-button" for="toggle-checkbox-202610030845080"><strong><span class="marker">コードと要約</span><span class="marker">(クリック)</span></strong></label><div class="toggle-content">
<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td><span class="red"><strong>❶</strong></span>公開用スクリプト作成_pub.txt：<br>要約：この workflow は、選択した *_exe.txt ファイルから公開用 *_pub.txt を生成する自動処理である。保存先は M1 側ボリュームに固定し、Dropbox へは直接書き込まない。メタ情報が無い場合は自動付与し、既存メタでは更新日時を除去、状態を「公開用」に変更する。本文から個人情報・キー・パス等を匿名化し、key_patterns.txt に基づく追加置換も行う。未置換の秘密候補を抽出して警告し、生成後は公開 URL とエンコード URL を表示・コピーする。付属のシェルスクリプトで生成物を Dropbox に rsync 同期する。</td></tr><tr><td><a href="https://imakat.com/script_list/?pubtxt=公開用スクリプト作成_pub.txt" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=zrU95MiY.png" alt="" style="width:120px; height:auto;"></a></td></tr><tr><td><span class="red"><strong>❷</strong></span>公開用スクリプトのリスト表示_pub.txt：<br>要約：WordPressのショートコードによる公開用TXT一覧を生成するコード。?pubtxt_dir パラメータで階層移動、見出しクリックで sort/order 切替が可能。pmedia/scripts_pub 配下のTXTのみ対象とし、@eaDir やドット始まり・key_patterns.txt を除外。<br>更新日時（mtime desc）→名前→サイズの優先順でソートし、パンくず表示も実装。各TXTはクリックで閲覧または &amp;dl=1 でUTF-8添付ダウンロード可。ディレクトリトラバーサル防止のため realpath 検証を行う安全設計。</td></tr><tr><td><a href="https://imakat.com/script_list/?pubtxt=公開用スクリプトのリスト表示_pub.txt" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=zrU95MiY.png" alt="" style="width:120px; height:auto;"></a></td></tr><tr><td><span class="red"><strong>❸</strong></span>scripts_pubフォルダからgドキュメントを生成_pub.txt：<br>要約：このシステムは、ローカルのスクリプトファイルをGoogleドキュメントに自動同期し、公開するためのものです。Googleドキュメント化することによりGemの読み込みが自動になります。<br><code>sync_docs.py</code>は、設定されたローカルフォルダから特定の拡張子を持つファイルを読み込み、更新日時順に整理します。これらのファイル内容を目次と共に整形し、Google Docs API経由で、指定された複数のGoogleドキュメントに分割して書き込みます（1ドキュメントあたり最大50ファイル）。既存内容を認証後に更新する機能を持ちます。<br><code>watcher.py</code>は<code>sync_docs.py</code>と連携し、監視対象フォルダ内のファイル変更をリアルタイムで検知します。変更後クールダウン期間を経て、自動的に<code>sync_docs.main_sync()</code>を呼び出し、Googleドキュメントへの同期処理を実行。ローカルファイルの更新を自動的にクラウドへ反映させます。<code>com.xxxxxxxx.docsupdater.plist</code>はmacOSのLaunchAgents設定ファイルで、システムの起動時に<code>watcher.py</code>を自動実行し、バックグラウンドでファイル監視とGoogleドキュメント同期プロセスを常駐させる役割を担います。<br>全体として、このシステムはローカルで管理するスクリプトやテキストファイルを常に最新の状態でGoogleドキュメント上に保ち、ウェブ公開可能な自動化ワークフローを提供します。</td></tr><tr><td><a href="https://imakat.com/script_list/?pubtxt=scripts_pubフォルダからgドキュメントを生成_pub.txt" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=zrU95MiY.png" alt="" style="width:120px; height:auto;"></a></td></tr><tr><td><span class="bold-red">❹</span>Antigravity(AIエージェント)に処理を指示するときの基調プロンプト：<br>XXXXXXシステムの実行局FACTORYは、Mac mini M1上の「ITスクリプト管理」を拠点に、設計図を現実環境に適合・定着・記録するAIアシスタントです。FACTORYはITスクリプト管理フォルダを徹底検索し、既存ファイルへの追記・修正を優先。コードは自律テストでエラー修正します。安全基準として、ITスクリプト管理フォルダ内は自律操作可ですが、他での削除等はオーナー承認必須。<code>rm -rf</code>等の破壊的コマンドは禁止、ゴミ箱へ移動等に置換します。機密情報は<code>.env</code>で管理し、報告は汎用形式で行います。記録では新規ファイル名はオーナーと相談、メタ情報と350～400字の要約を付与し、指定形式で出力。完了後、更新箇所をオーナーに報告します。<br>※XXXXXXは、ご自分の名前に変えてください。</td></tr><tr><td><a href="https://imakat.com/script_list/?pubtxt=AIエージェントに処理を指示するときの基調プロンプト_pub.txt" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=zrU95MiY.png" alt="" style="width:120px; height:auto;"></a></td></tr><tr><td>コード(スクリプト)をもっと知りたい方はこちらへ↓</td></tr><tr><td><a rel="noopener" target="_blank" href="https://gemini.google.com/gem/1Dp-NLSA5j5OXE3B1Ki2IaBRCvq4CGa6t?usp=sharing"><img decoding="async" src="https://imakat.com/rd.php?id=s7BMZHhB.png" alt="" style="width:120px; height:auto;"></a></td></tr></tbody></table></figure>
</div></div>



<h3 class="wp-block-heading">ポイント解説</h3>



<h4 class="wp-block-heading"><strong>ChatGPTからGeminiへ</strong></h4>



<p class="wp-block-paragraph">私のプログラム作成のパートナーは、はじめはChatGPTでしたが、最近になってGeminiへと移行しました。 その理由は開発してきたコードが増えて全部を記憶させて開発に利用することが困難になってきたからです。単価あたりの知識記憶容量がGeminiはChatGPTの約10倍あったのが決め手でした(2026年1月時点)。従って、これから説明する「知識の循環システム」が低コストで実現できるからです。</p>



<p class="wp-block-paragraph">ただし生成AIの選択ですが、将来どうするか全く分かりません。というのは、毎月くらい各社から高性能のモデルが登場して目移りするからです。ただ、GeminiはGoogle製なので、デジタルアセットの作成から利用、廃棄に至るインフラをほぼ全て提供できるGoogle内にいるので、今のところ一番底力があると思えます。Appleが本気を出せば別ですが。</p>



<p class="wp-block-paragraph">それでは、私が実践している**「コード（スクリプト）作成のエコシステム」**について、お話ししようと思います。</p>



<h4 class="wp-block-heading">１　<strong>開発：AIとの対話から生まれる「動く形」</strong></h4>



<p class="wp-block-paragraph">私のプログラム開発は、Geminiとの「対話」から始まります。 実現したいアイデアを、そのままAIに投げかけてみる。そこから質疑応答を重ね、ロジックを磨き、コードを作ってもらいテストを繰り返すというやり方です。</p>



<p class="wp-block-paragraph">最大のメリットは、自分の都合のいい時間に作業ができること、構文のエラーに悩まされる時間が減り仕組みづくりに集中できることでしょう。まずは**「動く形」を迅速に作り上げる**ことができる。これが、このシステムの第一の魅力です。</p>



<h4 class="wp-block-heading">２　<strong>見える化：情報を「資産」に変えるひと手間</strong></h4>



<p class="wp-block-paragraph">完成したコードをただ保存しておくだけでは、後で活かせません。「あれ、このpythonは何をするものだったかな？」と迷子になってしまいます。</p>



<p class="wp-block-paragraph">そこで私は、必ず**「コードの見える化」<strong>という工程を挟みます。 具体的には、Geminiにコードの</strong>「日本語要約」**を作成させ、それを冒頭に添付したtxtファイルを生成し、「ITスクリプト管理」フォルダへ収めます。</p>



<p class="wp-block-paragraph">さらに重要なのが<strong>セキュリティ</strong>です。 独自のルール（key_patterns.txt）に基づき、個人情報やAPIキーを機械的に「XXXXX」などへと置き換えます。こうして生成されたクリーンなファイルを、公開用の scripts_pub フォルダへ移動させます。 少し手間に見えるかもしれませんが、この工程が、「誰でも使える汎用的な知識資産」へと変身させるのです。</p>



<h4 class="wp-block-heading">３　<strong>公開と共有：ブログと「自分専用Gem」</strong></h4>



<p class="wp-block-paragraph">こうして整えられた知識資産は、2つのルートで新しい価値を生み出します。</p>



<p class="wp-block-paragraph">一つは、このブログです。 WordPress上の「公開スクリプト一覧」として整理し、訪問者に自由に役立てていただけるリソースとして開放しています。</p>



<p class="wp-block-paragraph">そしてもう一つが、**Geminiへのフィードバック（還流）**です。 これらのスクリプト群を「知識ソース」としてリンクした、私専用のGem（カスタムAI）を構築します。これはユーザーへのサポート窓口になると同時に、私自身が次のコードを生成するための、最強のデータベースになってくれるわけです。</p>



<p class="wp-block-paragraph">26年4月時点、Geminiに「ノートブック」という機能が追加になっています。ここにもセッションが使えますが、マルチモーダル機能が弱いため、画像の中身を読み取ることができないです。その意味でも、コード開発他で頻繁にスクショを添付する場合は、つまり<strong>画像を使うときは、マルチモーダル機能の強いGemまたはGemini本体のセッションを使うべき</strong>です。</p>



<h4 class="wp-block-heading"><strong>４　終わりなき進化のループ</strong></h4>



<p class="wp-block-paragraph">このシステムを運用していて改めて気づく最大の利点は、**「予習が不要」**になったことです。 プログラムに不具合が見つかったり、改善したくなったりした時、私のGeminiには既に過去のコードが「知識」として埋め込まれています。特段の準備をすることもなく、速やかに修正や拡張の開発に着手できるのです。</p>



<p class="wp-block-paragraph">修正して得られた新たな知見は、またシステムを通って知識ソースへ戻っていく。 回せば回すほど、AIは私の意図やコーディングの癖を深く学習し、精度が増していきます。まさに、終わりなき進化のループと言えるでしょう。</p>



<h4 class="wp-block-heading"><strong>5　</strong>ファイル管理系のアプリの生成・実行を、Antigravity任せにするのは禁物</h4>



<p class="wp-block-paragraph">動画を作った後で、改善として、「Antigravity」という、コードを作るだけではなくて実行テストから完成までやってくれるアプリを使えるようにしました。見てるだけで勝手に作業をしてくれる夢のようなアプリです。こういうアプリはAIエージェントと呼ばれています。ちなみにmodelとして大人気のClaudeも指定できます。しかしですね、非常に怖い側面を持っています。<strong>エンタメあるいは書類作成用途は、この「Antigravity」をぼおっと見てるだけでいいかも知れません。しかし、ファイル管理系のアプリ作成の場合は、作業を丸投げするのは、やめた方がいい</strong>です。「大事なファイルを消された！」という大失敗があちこちで起きているようです。</p>



<p class="wp-block-paragraph"><strong>ファイル管理系のシステムを生成する場合は、Antigravityは使わないで、</strong></p>



<div class="wp-block-cocoon-blocks-blank-box-1 blank-box block-box has-background has-watery-yellow-background-color">
<p class="wp-block-paragraph"><strong><span class="marker-under">Geminiにコードを書いてもらう→コードを実行ファイルにペーストする→Geminiに作ってもらったコマンドをターミナルに貼り付け実行する→ターミナルの返答をGeminiに報告する→正常に動くまで修正する→完成→コードをローカルのtxtファイルに保存して日本語要約を更新する→公開用ファイルを生成する</span></strong></p>



<p class="wp-block-paragraph"><span class="bold-red">※注意：コードに秘匿性のある文字列が含まれる場合は、そのチャットを、あとで削除するのが望ましいです。</span></p>
</div>



<p class="wp-block-paragraph">といったようにバトンリレーに人が挟まるような、慎重な形がよいと考えます。</p>



<p class="wp-block-paragraph"><br>Antigravityは、現在は無料ですが、いつ有料化されるかわからないので、そこも頼りきらないほうがいい理由でもあります。<br></p>



<h4 class="wp-block-heading"><strong>６　</strong>コード保存の最適解：なぜ「txtファイル」が最強なのか？</h4>



<p class="wp-block-paragraph">上記2で、要約とコードを「txtファイル」にまとめて保存する手順をご紹介しました。実はこの非常にシンプルで原始的な保存方法こそが、私が考えるエコシステムの「要」であり、最強の解決策です。</p>



<p class="wp-block-paragraph">上記5で触れたように、Antigravityのような便利なAIエージェントが登場しても、それに完全に依存するのは危険です。AIツールは凄まじいスピードで進化しており、数年後には全く別の会社の、全く新しいAIエージェントに乗り換えている可能性が十分にあります。</p>



<p class="wp-block-paragraph">そんな時、特定のアプリ専用のフォーマットや複雑なデータベースでコードを管理していると、移行時に解読できなくなるリスクが伴います。しかし、プレーンな「テキストファイル（.txt）」は、コンピューターの世界で最も普遍的なフォーマットです。要約と様々な言語のコードが1つのtxtファイルにまとまっていれば、将来どのようなAIエージェントをパートナーに選んだとしても、必ず解読・読み込みが可能です。<br><br>例えば、ノーコードツールは便利ですよ確かに。しかし、この作業方法を人に説明するのが難しいという、笑えない欠点があります。有名なAppSheetを使ったとします。しかしこれを、「どんな画面を開いて、どの項目を選んで、そこへどのような算式を書き込んで、どうする」といった手順は、文章の手順書として記述することにならざるを得ません。なにせノーコードですから。このノーコードツールでの内容も、一つにまとめたいシステムの一部なのです。そうしたものもtxtファイルなら含むことができます。</p>



<figure class="wp-block-image size-large is-resized"><a href="https://imakat.com/rd.php?id=gbFJyujp.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=gbFJyujp.png" alt="" style="aspect-ratio:1.8333606154853495;width:800px;height:auto"/></a></figure>



<p class="wp-block-paragraph">目まぐるしく変わるAI時代において、環境の変化に左右されず、確実に自分の資産を守り継承できる。シンプルゆえに、このtxtファイルでの保存方法が「最強」だと言えます。</p>



<h4 class="wp-block-heading"><strong>【おわりに】</strong>まだまだ混沌とした領域、to be continued</h4>



<p class="wp-block-paragraph">今回は「プログラム作成」を例に挙げましたが、この**「情報の整理・変換・再学習」という循環**は、文章作成や研究、あるいは趣味の記録など、あらゆる分野に応用が可能だと感じています。</p>



<p class="wp-block-paragraph">作業の進め方は、ゴールまでの間をステップ化して、少しずつ着実に進む方法がベストです。</p>



<p class="wp-block-paragraph">一つの記事には、「おわり」があるわけですが、このコード生成のエコシステムの構築は、実は、今、始まったばかりで、この記事を書き終えた今、もう、リフォームを考えています。私にとってAntigravityは専門的過ぎるし勝手に動くので全くのブラックボックスになることはリスクが大きいです。</p>



<p class="wp-block-paragraph">ちょっと方向を変えて。</p>



<p class="wp-block-paragraph">具体的には、Gemini、Gem、 NotebookLM、 GoogleAIStudioの連携を使って、コード生成工房をもっと便利に改造したいです。</p>



<p class="wp-block-paragraph">実際、ほとんど毎日のように、エラーや不具合を直したり、小道具のようなアプリを作ったりしていますが、それを行う、私の作業小屋ですね。それを改造したいと思います。</p>



<p class="wp-block-paragraph">私は高齢者ではありますが、こういった新しい技術は、若者だけのものではありません。むしろ、これまで蓄積してきた多くの知識や経験を整理し、形にするためにこそ、AIというパートナーは大きな力を貸してくれるようにも思えます。企画する力、構想する力は、 高齢者こそ備わっているのでは、と思っています。</p>



<p class="wp-block-paragraph">to be continued.</p>



<p class="wp-block-paragraph"><br>以上</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">28530</post-id>	</item>
	</channel>
</rss>
