這篇文章記錄了我昨天臨時抱佛腳,花了一下午加一整晚,利用 Gemini Gems 為兩門高三選修課(選修地科與生涯規劃)打造專屬「AI 對談助教」的實戰經驗。
在地科課中,我讓 AI 提議並建構了一個涵蓋 60 個前瞻議題的跨領域知識庫,引導學生找尋專屬報告主題,並導入「預先評分」機制;在生涯規劃課中,AI 則化身為「人格拷問官」,將心理學理論結合台灣高中生情境,最後為學生繪製一張專屬的特質圖像。
雖然實際在課堂上運用時,發生了「一開始給錯連結」以及「對話紀錄無法分享只能靠截圖」等真實的意外插曲,但看著學生順利透過 AI 進行深度的自我探索,讓我更確信:只要老師設計好資料庫與引導邏輯,AI 絕對是教學現場最得力的助手。歡迎大家點開內文的連結親自體驗!
作者彙整: Han-Chiang Chou
【開發心得】與 AI 奮戰兩週:宮澤賢治主題實地解謎手遊上架實錄
Gemini的Deep Research產出研究報告中的LaTex語法轉換
如果Gemini的Deep Research產出研究報告裡面有數學公式或上下標,研究報告匯出成Google文件時,就會有很多$….$的符號,無法轉換成正確格式。
找Gemini解決這個問題非常不成功,就換成ChatGPT,大致上解決了。
解決的方法是土法煉鋼,將文章中LaTex的語法一一對照取代,用窮舉式的寫法,一個代碼一個代碼設定在程式碼裡面。未來若遇到程式不認得的代碼,就再加進去。
當初有個瓶頸是替換LaTex代碼時,文章格式會跑掉,但AI最後還是想辦法解決了。
程式碼寫在Google文件的Apps Script裡面,跟著一份Google文件走。所以複製這份Google文件就可以有這個功能,不用輸入程式碼。
這是可以複製去用的文件範本,點選連結後,網頁畫面就會直接要求你建立一個副本,文件中有使用說明。
結尾有我和AI的對話,其中有如何將APP Script加入Google文件的流程。未來如果有LaTex代碼沒解析到的,可以把程式碼貼給AI叫他加,或是自己手動加在程式碼裡面。
程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | function onOpen() { DocumentApp.getUi() .createMenu('LaTeX 轉換') .addItem('建立轉換後的新文件(保留格式)', 'createLatexConvertedCopy') .addToUi(); } // 1. 複製整份文件 → 2. 在副本中逐段處理 $...$ 與 frac{...}{...} function createLatexConvertedCopy() { var srcDoc = DocumentApp.getActiveDocument(); var srcId = srcDoc.getId(); // 1. 用 Drive 複製整份文件(格式、圖片、表格都保留) var file = DriveApp.getFileById(srcId); var copy = file.makeCopy(srcDoc.getName() + '(LaTeX 轉換版)'); var newDoc = DocumentApp.openById(copy.getId()); var body = newDoc.getBody(); // 2. 在副本裡處理所有段落 / 清單 / 表格中的文字 processElement_(body); newDoc.saveAndClose(); DocumentApp.getUi().alert( '已建立 LaTeX 轉換版文件(格式及圖片保留):\n' + newDoc.getUrl() ); } /** * 遞迴走訪整個文件樹: * - Paragraph / ListItem → 以「整行文字」為單位處理 * - Table / Cell → 繼續往下走 */ function processElement_(elem) { var ElementType = DocumentApp.ElementType; var type = elem.getType && elem.getType(); if (type === ElementType.PARAGRAPH || type === ElementType.LIST_ITEM) { var text = elem.editAsText(); if (text) { convertParagraphText_(text); } } if (elem.getNumChildren) { var n = elem.getNumChildren(); for (var i = 0; i < n; i++) { processElement_(elem.getChild(i)); } } } /** * 對單一段落 (editAsText): * 1. 先處理整段裡所有 $...$ * 2. 再處理「裸的」 frac{a}{b} */ function convertParagraphText_(text) { var full = text.getText(); if (full.indexOf('$') === -1 && full.indexOf('frac{') === -1) return; // --- 找出所有 $...$ 的位置(用原始 full 索引)--- var dollarMatches = []; var re = /\$([^$]+)\$/g; var m; while ((m = re.exec(full)) !== null) { dollarMatches.push({ start: m.index, end: re.lastIndex - 1, inner: m[1] }); } // 從後往前改,避免索引被前面的修改影響 for (var i = dollarMatches.length - 1; i >= 0; i--) { var dm = dollarMatches[i]; var converted = latexToUnicode_(dm.inner); text.deleteText(dm.start, dm.end); if (converted.length > 0) { text.insertText(dm.start, converted); } } // --- 再處理沒有 $ 包起來的 frac{a}{b} --- full = text.getText(); var fracRe = /frac\{([^}]+)\}\{([^}]+)\}/g; var fracMatches = []; while ((m = fracRe.exec(full)) !== null) { fracMatches.push({ start: m.index, end: fracRe.lastIndex - 1, num: m[1], den: m[2] }); } for (var j = fracMatches.length - 1; j >= 0; j--) { var fm = fracMatches[j]; var rep = '(' + fm.num + '/' + fm.den + ')'; text.deleteText(fm.start, fm.end); text.insertText(fm.start, rep); } } /** * 處理一小段 LaTeX(不含外層 $) * 例如:"V_E", "R_{\\text{ref}}", "\\mu = 3.986 \\times 10^{14}" */ function latexToUnicode_(latex) { var t = latex; // 1. \text{ km } → km t = t.replace(/\\text\{([^}]*)\}/g, '$1'); // 2. \frac{a}{b} → (a/b) t = t.replace(/\\frac\{([^}]+)\}\{([^}]+)\}/g, function(match, num, den) { return '(' + num + '/' + den + ')'; }); // 3. LaTeX 指令 → 對應符號(μ, ρ, ×, ≈, ∞...) var map = getSymbolMap_(); t = t.replace(/\\[a-zA-Z]+/g, function(cmd) { return map[cmd] || cmd.slice(1); // 未定義 → 去掉反斜線 }); // 4. _{...} / _x / ^{...} / ^x → Unicode 上下標 return applySubSupUnicode_(t); } /** * 把 _、^ 語法變成 Unicode 上/下標字元 */ function applySubSupUnicode_(str) { var result = ''; var i = 0; while (i < str.length) { var ch = str.charAt(i); if ((ch === '_' || ch === '^') && i + 1 < str.length) { var isSub = (ch === '_'); var next = str.charAt(i + 1); var content = ''; var j; if (next === '{') { j = i + 2; while (j < str.length && str.charAt(j) !== '}') { content += str.charAt(j); j++; } if (j < str.length && str.charAt(j) === '}') j++; } else { content = next; j = i + 2; } result += mapToSubSup_(content, isSub); i = j; } else { result += ch; i++; } } return result; } /** * 把 content 裡每個字元映射成上標/下標 * 支援 a–z / A–Z / 0–9 */ function mapToSubSup_(content, isSub) { // 下標對照表 var subMap = { '0':'₀','1':'₁','2':'₂','3':'₃','4':'₄','5':'₅','6':'₆','7':'₇','8':'₈','9':'₉', 'a':'ₐ','b':'ᵦ','c':'꜀','d':'꜁','e':'ₑ','f':'ᵮ','g':'ᵧ','h':'ₕ', 'i':'ᵢ','j':'ⱼ','k':'ₖ','l':'ₗ','m':'ₘ','n':'ₙ','o':'ₒ','p':'ₚ', 'q':'ᑫ','r':'ᵣ','s':'ₛ','t':'ₜ','u':'ᵤ','v':'ᵥ','w':'𝓌','x':'ₓ', 'y':'ᵧ','z':'𝓏', // 大寫下標(無正式 Unicode,下列用近似字元) 'A':'ₐ','B':'ᵦ','C':'꜀','D':'ᵭ','E':'ₑ','F':'𝆑','G':'ᵍ', 'H':'ₕ','I':'ᵢ','J':'ⱼ','K':'ₖ','L':'ₗ','M':'ₘ','N':'ₙ','O':'ₒ', 'P':'ₚ','Q':'ᑫ','R':'ᵣ','S':'ₛ','T':'ₜ','U':'ᵤ','V':'ᵥ', 'W':'𝓌','X':'ₓ','Y':'ᵧ','Z':'𝓏' }; // 上標對照表 var supMap = { '0':'⁰','1':'¹','2':'²','3':'³','4':'⁴','5':'⁵','6':'⁶','7':'⁷','8':'⁸','9':'⁹', 'a':'ᵃ','b':'ᵇ','c':'ᶜ','d':'ᵈ','e':'ᵉ','f':'ᶠ','g':'ᵍ','h':'ʰ', 'i':'ⁱ','j':'ʲ','k':'ᵏ','l':'ˡ','m':'ᵐ','n':'ⁿ','o':'ᵒ','p':'ᵖ', 'q':'ᑫ','r':'ʳ','s':'ˢ','t':'ᵗ','u':'ᵘ','v':'ᵛ','w':'ʷ','x':'ˣ', 'y':'ʸ','z':'ᶻ', // 大寫上標 'A':'ᴬ','B':'ᴮ','C':'ᶜ','D':'ᴰ','E':'ᴱ','F':'ᶠ','G':'ᴳ', 'H':'ᴴ','I':'ᴵ','J':'ᴶ','K':'ᴷ','L':'ᴸ','M':'ᴹ','N':'ᴺ', 'O':'ᴼ','P':'ᴾ','Q':'ᑫ','R':'ᴿ','S':'ˢ','T':'ᵀ','U':'ᵁ', 'V':'ⱽ','W':'ᵂ','X':'ˣ','Y':'ʸ','Z':'ᶻ' }; var table = isSub ? subMap : supMap; var out = ''; for (var i = 0; i < content.length; i++) { var c = content.charAt(i); out += (table[c] || c); } return out; } /** * LaTeX → Unicode 符號表(可再擴充) */ function getSymbolMap_() { return { // 希臘字母 '\\mu': 'μ', '\\rho': 'ρ', '\\alpha': 'α', '\\beta': 'β', '\\gamma': 'γ', '\\delta': 'δ', '\\epsilon': 'ε', '\\varepsilon': 'ε', '\\theta': 'θ', '\\lambda': 'λ', '\\sigma': 'σ', '\\omega': 'ω', '\\Omega': 'Ω', // 常用數學符號 '\\infty': '∞', '\\times': '×', '\\cdot': '·', '\\approx': '≈', '\\propto': '∝', '\\leq': '≤', '\\geq': '≥', '\\neq': '≠', '\\gg': '≫', '\\ll': '≪', '\\pm': '±', '\\sqrt': '√' }; } |
程式碼寫在Google文件的Apps Script裡面,跟著一份Google文件走。所以複製這份Google文件就可以有這個功能,不用輸入程式碼。
這是可以複製去用的文件範本,點選連結後,網頁畫面就會直接要求你建立一個副本,文件中有使用說明。
這是和AI的對話過程。
批次編輯商品屬性
WooCommerce 後台清單頁,上方可用分類/標籤篩選;提供母子式下拉選單,批次為勾選商品加入指定屬性與屬性項目(若無該屬性則先建立並排在最後)。列表移除SKU欄位;每個全域屬性各自成欄顯示;屬性類別以 slug 升冪排列;欄位標題可換行;外層視需要允許水平滾動。
閱讀全文
全部商品管理篩選頁面
再全部商品的管理頁面,可以用標籤篩選商品。
閱讀全文
Split Post 很棒的文章分頁外掛
項目符號的形式
order list的項目:
- none ( 沒有符號 )
- cjk-ideographic ( 一、二、三 )
- decimal ( 1、2、3 )
- decimal-leading-zero ( 01、02、03 )
- lower-alpha ( a、b、c )
- upper-alpha ( A、B、C )
- lower-roman ( i、ii、iii )
- upper-roman ( I、II、III )
- initial
語法:
1 | <ol style="list-style-type:upper-alpha"> |
unorder list的項目:
- disc
- circle
- square
- none
1 | <li style="list-style-type: circle;"> |
大量新增wordpress部落格文章的外掛 – WP Ultimate CSV Importer
大概很少人需要用到這種「一次在wordpress部落格新增很多文章」的工具,卻是我非常重要的工具!
因為我的加菲貓漫畫部落格(http://mygarfield.org/),常常一次張貼幾十篇甚至上百篇翻譯,其中最辛苦的步驟是建立「張貼日期」。因為每一篇漫畫都有原始的張貼日期,但是我都累積很多篇才一起張貼,所以要設定每一篇的張貼日期就會非常痛苦。
過去我是用mass-page-maker這個外掛,它可以設定每一篇文章的張貼時間間隔,例如設定24小時,那他大量產生的新文章就會是每天一則,然後我再編寫內容就可以。不過這個外掛9年前就停止更新,而且最近終於無法正常使用了。
網路上大量新增文章的外掛其實不少,但很少有可以設定張貼日期的功能。後來找到以CSV匯入文章的方式似乎可行,只要在EXCEL檔裡面把每篇文章的張貼日期先設好,匯出成CSV檔再上傳wordpress就好。
目前我找到最好用的是WP Ultimate CSV Importer這個外掛,他可以在CSV檔上傳之後,讓使用者選擇CSV檔案內的每個欄位,要對應到wordpress文章的哪些欄位,非常好用。
總而言之,加菲貓漫畫的翻譯工作又可以繼續更新了!
Linux系統中有特殊符號的檔案刪除或更名
用ls -i找到檔案的inode number,然後用以下語法刪除或更名
find -inum 000000000 -exec rm {} \;
find -inum 000000000 -exec mv {} newname \;
0000000000就是剛剛ls -i找到的inode number
newname是想要更名的新檔案名稱
資料來源:My Linux Note
google文件無法使用自然輸入法?!其實現在chrome不用安裝輸入法了,有線上輸入法可以使用!
最近突然發現自然輸入法無法在Google文件上輸入文字(Chrome瀏覽器),下載新酷音就可以輸入文字,但選字時看不到游標。原來是Google文件現在已經提供線上輸入法,可能是程式上的衝突,導致電腦系統的輸入法反而出問題。所以雖然要熟悉一個新輸入法,但不用安裝輸入法實在太棒,特別是到了其他國家沒有中文輸入法,或是突然想輸入日文還得另外安裝輸入法,應該是「利大於弊」吧!
呼叫線上輸入法的方式:
Windows:Ctrl + Shift + K
Mac Os:Cmd + Shift + K
全形標點符號:
逗號(,):Shift + ,
句號(。):Shift + .
問號(?):Shift + /
冒號(:):Shift + ;
分號(;):切換為全型後(shift+空白鍵 )再按 ;
頓號(、):\
驚嘆號(!):Shift + 1
上引號(「):[
下引號(」):]
左括號(():Shift + 9
右括號()):Shift + 0
全形字元:Shift + 空白鍵
詳細介紹:
Google 輸入工具!支援繁體中文注音輸入、拼音、日文、韓文、手寫辨識..等 40 國語言輸入法(Google Chrome)by 重灌狂人

