<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>LINE Bot｜林鼎淵 Dean Lin</title>
    <link>https://deanlin.net/tags/line-bot/</link>
    <image><url>https://deanlin.net/images/author_hu_aa256fc934e9a932.jpg</url><title>LINE Bot｜林鼎淵 Dean Lin</title><link>https://deanlin.net/tags/line-bot/</link><width>144</width><height>144</height></image>
    <description>林鼎淵（Dean Lin）的部落格：生成式 AI 企業內訓講師、外商資安公司軟體專家、7 本書作者。400 多篇文章用白話分享生成式 AI 實戰、Claude Code 與 Vibe Coding 教學、團隊合作與職場成長。</description>
    <generator>Hugo</generator>
    <language>zh-tw</language>
    <copyright>© 2020–2026 林鼎淵 Dean Lin</copyright>
    <lastBuildDate>Wed, 25 Jan 2023 15:24:33 +0800</lastBuildDate>
    <atom:link href="https://deanlin.net/tags/line-bot/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>靠問 ChatGPT 寫程式，能完成 OpenAI &amp; Linebot 的 Side Project 嗎？（下）</title>
      <link>https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/</link>
      <pubDate>Wed, 25 Jan 2023 15:24:33 +0800</pubDate>
      <guid>https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>AI 實戰</category>
      <description>在這篇文章中，我們要來設定 Line 的 webhook，並測試 ChatGPT 寫的程式是否可以正確執行；並告訴讀者遇到問題時，我們可以從哪些面向來思考、解決；最後於文末給想用 ChatGPT 寫程式、學程式的朋友一些建議。</description>
      <media:content url="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-og_hu_b00ae86497f1183.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<p>在<a href="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/">上一篇文章</a>中，我們好不容易請 ChatGPT 完成 OpenAI-Linebot 的專案，並順利啟動。</p>
<p>在這篇文章中，我們要來設定 Line 的 webhook，並測試 ChatGPT 寫的程式是否可以正確執行；並告訴讀者遇到問題時，我們可以從哪些面向來思考、解決；最後於文末給想用 ChatGPT 寫程式、學程式的朋友一些建議。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-01.webp" width="1260" height="689" alt="靠問 ChatGPT 寫程式，能完成 OpenAI &amp; Linebot 的 Side Project 嗎？（下）（圖 1）" fetchpriority="high" decoding="async"></p>
<pre tabindex="0"><code>大綱

▋ 在 local 建立一個可以讓 Line 訪問的 HTTP server（ngrok）
▋ 設定 Line 的 webhook
▋ 測試功能＆痛苦的 Debug 之路
▋ 結論：給想用 ChatGPT 寫程式、學程式的朋友一些建議
</code></pre><h2 id="在-local-建立一個可以讓-line-訪問的-http-serverngrok">在 local 建立一個可以讓 Line 訪問的 HTTP server（ngrok）<a class="h-anchor" href="#%e5%9c%a8-local-%e5%bb%ba%e7%ab%8b%e4%b8%80%e5%80%8b%e5%8f%af%e4%bb%a5%e8%ae%93-line-%e8%a8%aa%e5%95%8f%e7%9a%84-http-serverngrok" aria-label="這個段落的連結"></a></h2>
<p>上一篇文章中，專案是在本地啟動的，因此他的網址是 <a href="http://localhost:3000">http://localhost:3000</a> ，而 Line 的 webhook 是無法接受本地網址的。</p>
<p>為了方便 Debug，我這邊選擇在 local 建立一個可以讓 Line 訪問的 HTTP server，具體的方案我們來詢問一下 ChatGPT。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-02.webp" width="1077" height="537" alt="在 local 建立一個可以讓 Line 訪問的 HTTP server（ngrok）（圖 2）" loading="lazy" decoding="async"></p>
<p>這邊我選用「ngrok」的方案，並在指定「作業系統」的狀態下，請 ChatGPT 告訴我接下來該怎麼做。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-03.webp" width="1086" height="705" alt="在 local 建立一個可以讓 Line 訪問的 HTTP server（ngrok）（圖 3）" loading="lazy" decoding="async"></p>
<p>接下來我們就按造建議的步驟來實作看看。</p>
<p><strong>SETP 1</strong>：先到 ngrok 的官網下載 ngrok 的 Mac 版本： <a href="https://ngrok.com/download">https://ngrok.com/download</a> 。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-04.webp" width="1400" height="1296" alt="在 local 建立一個可以讓 Line 訪問的 HTTP server（ngrok）（圖 4）" loading="lazy" decoding="async"></p>
<blockquote>
<p>提醒讀者，要先確認自己 mac 的處理器是 Intel 還是 Apple Silicon 喔！</p>
</blockquote>
<p><strong>SETP 2</strong>：解壓縮下載的檔案，並將 ngrok 放入您的 PATH 中 (例如: /usr/local/bin)</p>
<p>解壓縮檔案後，你會得到一個 ngrok 的值行檔，其實你就算放在 download 的資料夾也能執行，不過放到 bin 的資料夾下可以在任何位置執行。</p>
<p>下面說明一下 mac 進入 bin 資料夾的步驟：「到 mac 桌面」or「點擊 Finder」➝ 「前往」➝ 「前往資料夾」➝ 輸入「/usr/local/bin」➝ 把「ngrok 值行檔」丟進去。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-05.webp" width="1108" height="892" alt="在 local 建立一個可以讓 Line 訪問的 HTTP server（ngrok）（圖 5）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-06.webp" width="956" height="456" alt="在 local 建立一個可以讓 Line 訪問的 HTTP server（ngrok）（圖 6）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-07.webp" width="1400" height="670" alt="在 local 建立一個可以讓 Line 訪問的 HTTP server（ngrok）（圖 7）" loading="lazy" decoding="async"></p>
<p><strong>SETP 3</strong>：打開終端機，輸入 <code>ngrok http 3000</code> (3000 是您的本地環境的 HTTP Server 的通訊埠)，啟動 ngrok。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-08.webp" width="1400" height="486" alt="在 local 建立一個可以讓 Line 訪問的 HTTP server（ngrok）（圖 8）" loading="lazy" decoding="async"></p>
<p><strong>SETP 4</strong>：ngrok 將會顯示一個可供外部訪問的 URL（上圖紅框處 <code>https://xxxx.ngrok.io</code>），您可以在 LINE 的 Developer Console 中設定 webhook 的 URL。</p>
<blockquote>
<p><strong>小提醒</strong>：Session 2 小時後會過期，到時再重新執行一次 <code>ngrok http 3000</code> 就好了，然後別忘記把新的 URL 設定到 Line 的 webhook。</p>
</blockquote>
<hr>
<h2 id="-設定-line-的-webhook">設定 Line 的 webhook<a class="h-anchor" href="#-%e8%a8%ad%e5%ae%9a-line-%e7%9a%84-webhook" aria-label="這個段落的連結"></a></h2>
<p>因為設定步驟很簡單，我就不特別問 ChatGPT 了。</p>
<p><strong>SETP 1</strong>：在 Messaging API 的 WebhookURL 貼上剛剛的的網址，並於後面加上 <code>/webhook</code>（那是我們程式設定的 API 路徑）。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-09.webp" width="1077" height="563" alt="設定 Line 的 webhook（圖 9）" loading="lazy" decoding="async"></p>
<p><strong>SETP 2</strong>：按下「Verify」後得到 Success 就代表有成功聯通嚕！</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-10.webp" width="1000" height="397" alt="設定 Line 的 webhook（圖 10）" loading="lazy" decoding="async"></p>
<p><strong>SETP 3</strong>：在 Messaging API 取得 Linebot 的 LineID，並把他加入好友。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-11.webp" width="739" height="332" alt="設定 Line 的 webhook（圖 11）" loading="lazy" decoding="async"></p>
<p>加入好友後，他會跟你打招呼。</p>
<p>但當你很興奮的傳訊息給他時，他的回覆語氣一點都不像是 ChatGPT。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-12.webp" width="1382" height="1006" alt="設定 Line 的 webhook（圖 12）" loading="lazy" decoding="async"></p>
<p>雖然到這裡我們已經知道出事了，但還是先把下面的步驟做完吧。</p>
<p><strong>SETP 4</strong>：在 Messaging API 關閉自動回覆（Auto-reply messages）與打招呼（Greeting messages）。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-13.webp" width="1300" height="588" alt="設定 Line 的 webhook（圖 13）" loading="lazy" decoding="async"></p>
<blockquote>
<p>因為自動回覆（Auto-reply messages）會干擾 Debug 所以建議關閉，至於打招呼（Greeting messages）要不要關閉就看你自己。</p>
</blockquote>
<hr>
<h2 id="測試功能痛苦的-debug-之路">測試功能＆痛苦的 Debug 之路<a class="h-anchor" href="#%e6%b8%ac%e8%a9%a6%e5%8a%9f%e8%83%bd%e7%97%9b%e8%8b%a6%e7%9a%84-debug-%e4%b9%8b%e8%b7%af" aria-label="這個段落的連結"></a></h2>
<p>上面 Webhook URL 的 Verify 得到 200 只是證明這條路有打通，如果把畫面切到 ngrok，會發現許多 500 的錯誤訊息。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-14.webp" width="1400" height="708" alt="測試功能＆痛苦的 Debug 之路（圖 14）" loading="lazy" decoding="async"></p>
<h3 id="-上一篇-chatgpt-給的程式有哪些錯誤">上一篇 ChatGPT 給的程式有哪些錯誤？<a class="h-anchor" href="#-%e4%b8%8a%e4%b8%80%e7%af%87-chatgpt-%e7%b5%a6%e7%9a%84%e7%a8%8b%e5%bc%8f%e6%9c%89%e5%93%aa%e4%ba%9b%e9%8c%af%e8%aa%a4" aria-label="這個段落的連結"></a></h3>
<p>回到程式，你會發現有「TypeError: Cannot read properties of undefined (reading ‘events’)」的錯誤。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-15.webp" width="1400" height="384" alt="上一篇 ChatGPT 給的程式有哪些錯誤？（圖 15）" loading="lazy" decoding="async"></p>
<p>如果你把這個問題拿去詢問 ChatGPT，會收到一大堆鬼打牆的回覆。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-16.webp" width="1067" height="728" alt="上一篇 ChatGPT 給的程式有哪些錯誤？（圖 16）" loading="lazy" decoding="async"></p>
<p>這邊筆者就直接告訴大家為什麼會有各式各樣的錯誤：</p>
<ul>
<li>「@line/bot-sdk」套件使用方式錯誤</li>
<li>「openai」套件使用方式錯誤</li>
</ul>
<p>你沒看錯，要實作的兩個套件，ChatGPT 的使用方式都是有問題的。</p>
<h3 id="-讓-chatgpt-擔任程式專家改用英文詢問">讓 ChatGPT 擔任程式專家，改用英文詢問<a class="h-anchor" href="#-%e8%ae%93-chatgpt-%e6%93%94%e4%bb%bb%e7%a8%8b%e5%bc%8f%e5%b0%88%e5%ae%b6%e6%94%b9%e7%94%a8%e8%8b%b1%e6%96%87%e8%a9%a2%e5%95%8f" aria-label="這個段落的連結"></a></h3>
<p>為了避免冤枉好人，我這次改成用英文詢問，並讓 ChatGPT 擔任程式專家來撰寫，這是他給出的新回覆：</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#ff7b72">const</span> line <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#39;@line/bot-sdk&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> express <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#39;express&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> openai <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#39;openai&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>openai.apiKey <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;YOUR_API_KEY&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> config <span style="color:#ff7b72;font-weight:bold">=</span> {
</span></span><span style="display:flex;"><span>  channelAccessToken<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#39;YOUR_CHANNEL_ACCESS_TOKEN&#39;</span>,
</span></span><span style="display:flex;"><span>  channelSecret<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#39;YOUR_CHANNEL_SECRET&#39;</span>
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> client <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#ff7b72">new</span> line.Client(config);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> app <span style="color:#ff7b72;font-weight:bold">=</span> express();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app.post(<span style="color:#a5d6ff">&#39;/webhook&#39;</span>, line.middleware(config), (req, res) =&gt; {
</span></span><span style="display:flex;"><span>  Promise
</span></span><span style="display:flex;"><span>    .all(req.body.events.map(handleEvent))
</span></span><span style="display:flex;"><span>    .then((result) =&gt; res.json(result))
</span></span><span style="display:flex;"><span>    .<span style="color:#ff7b72">catch</span>((err) =&gt; {
</span></span><span style="display:flex;"><span>      console.error(err);
</span></span><span style="display:flex;"><span>      res.status(<span style="color:#a5d6ff">500</span>).end();
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">function</span> handleEvent (event) {
</span></span><span style="display:flex;"><span>  <span style="color:#ff7b72">if</span> (event.type <span style="color:#ff7b72;font-weight:bold">!==</span> <span style="color:#a5d6ff">&#39;message&#39;</span> <span style="color:#ff7b72;font-weight:bold">||</span> event.message.type <span style="color:#ff7b72;font-weight:bold">!==</span> <span style="color:#a5d6ff">&#39;text&#39;</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> Promise.resolve(<span style="color:#79c0ff">null</span>);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff7b72">return</span> openai
</span></span><span style="display:flex;"><span>    .engines
</span></span><span style="display:flex;"><span>    .completions
</span></span><span style="display:flex;"><span>    .create({
</span></span><span style="display:flex;"><span>      prompt<span style="color:#ff7b72;font-weight:bold">:</span> event.message.text,
</span></span><span style="display:flex;"><span>      engine<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#34;text-davinci-002&#34;</span>,
</span></span><span style="display:flex;"><span>      maxTokens<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">100</span>
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>    .then((completions) =&gt; {
</span></span><span style="display:flex;"><span>      <span style="color:#ff7b72">const</span> message <span style="color:#ff7b72;font-weight:bold">=</span> completions.choices[<span style="color:#a5d6ff">0</span>].text;
</span></span><span style="display:flex;"><span>      <span style="color:#ff7b72">return</span> client.replyMessage(event.replyToken, {
</span></span><span style="display:flex;"><span>        type<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#39;text&#39;</span>,
</span></span><span style="display:flex;"><span>        text<span style="color:#ff7b72;font-weight:bold">:</span> message
</span></span><span style="display:flex;"><span>      });
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app.listen(<span style="color:#a5d6ff">3000</span>);
</span></span><span style="display:flex;"><span>console.log(<span style="color:#a5d6ff">&#39;Linebot is running on 3000 port&#39;</span>);
</span></span></code></pre></div><p>果然專家就是比較厲害，錯誤訊息變得不一樣了！</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-17.webp" width="1400" height="292" alt="讓 ChatGPT 擔任程式專家，改用英文詢問（圖 17）" loading="lazy" decoding="async"></p>
<p>但這個錯誤並沒有辦法靠詢問 ChatGPT 解決（他會再次鬼打牆）。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-18.webp" width="1083" height="665" alt="讓 ChatGPT 擔任程式專家，改用英文詢問（圖 18）" loading="lazy" decoding="async"></p>
<h3 id="-好吧最後還是得靠自己處理">好吧…最後還是得靠自己處理<a class="h-anchor" href="#-%e5%a5%bd%e5%90%a7%e6%9c%80%e5%be%8c%e9%82%84%e6%98%af%e5%be%97%e9%9d%a0%e8%87%aa%e5%b7%b1%e8%99%95%e7%90%86" aria-label="這個段落的連結"></a></h3>
<p>因為我看錯誤的源頭出在 openai 套件，所以我就去官網研究了一下：<a href="https://www.npmjs.com/package/openai">https://www.npmjs.com/package/openai</a></p>
<p>先給大家看一下官網給的範例程式：</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#ff7b72">const</span> { Configuration, OpenAIApi } <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#34;openai&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> configuration <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#ff7b72">new</span> Configuration({
</span></span><span style="display:flex;"><span>  apiKey<span style="color:#ff7b72;font-weight:bold">:</span> process.env.OPENAI_API_KEY,
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> openai <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#ff7b72">new</span> OpenAIApi(configuration);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> completion <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#ff7b72">await</span> openai.createCompletion({
</span></span><span style="display:flex;"><span>  model<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#34;text-davinci-002&#34;</span>,
</span></span><span style="display:flex;"><span>  prompt<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#34;Hello world&#34;</span>,
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>console.log(completion.data.choices[<span style="color:#a5d6ff">0</span>].text);
</span></span></code></pre></div><p><strong>如果把他跟 ChatGPT 給的程式做比對，會發現 ChatGPT 的使用方式根本是錯的</strong>，下面筆者就直接把修改好的程式放上來，調整過的部分有在旁邊用註解說明：</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>require(<span style="color:#a5d6ff">&#39;dotenv&#39;</span>).config(); <span style="color:#8b949e;font-style:italic">// 皆採用 .env 讀取
</span></span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> line <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#39;@line/bot-sdk&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> express <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#39;express&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> { Configuration, OpenAIApi } <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#34;openai&#34;</span>); <span style="color:#8b949e;font-style:italic">// 他套件使用方式錯誤，我直接改掉
</span></span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> configuration <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#ff7b72">new</span> Configuration({
</span></span><span style="display:flex;"><span>  apiKey<span style="color:#ff7b72;font-weight:bold">:</span> process.env.OPENAI_API_KEY,
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> openai <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#ff7b72">new</span> OpenAIApi(configuration);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> config <span style="color:#ff7b72;font-weight:bold">=</span> {
</span></span><span style="display:flex;"><span>  channelAccessToken<span style="color:#ff7b72;font-weight:bold">:</span> process.env.CHANNEL_ACCESS_TOKEN,
</span></span><span style="display:flex;"><span>  channelSecret<span style="color:#ff7b72;font-weight:bold">:</span> process.env.CHANNEL_SECRET,
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> client <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#ff7b72">new</span> line.Client(config);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> app <span style="color:#ff7b72;font-weight:bold">=</span> express();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app.post(<span style="color:#a5d6ff">&#39;/webhook&#39;</span>, line.middleware(config), (req, res) =&gt; {
</span></span><span style="display:flex;"><span>  Promise
</span></span><span style="display:flex;"><span>    .all(req.body.events.map(handleEvent))
</span></span><span style="display:flex;"><span>    .then((result) =&gt; res.json(result))
</span></span><span style="display:flex;"><span>    .<span style="color:#ff7b72">catch</span>((err) =&gt; {
</span></span><span style="display:flex;"><span>      console.error(err);
</span></span><span style="display:flex;"><span>      res.status(<span style="color:#a5d6ff">500</span>).end();
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">function</span> handleEvent (event) {
</span></span><span style="display:flex;"><span>  <span style="color:#ff7b72">if</span> (event.type <span style="color:#ff7b72;font-weight:bold">!==</span> <span style="color:#a5d6ff">&#39;message&#39;</span> <span style="color:#ff7b72;font-weight:bold">||</span> event.message.type <span style="color:#ff7b72;font-weight:bold">!==</span> <span style="color:#a5d6ff">&#39;text&#39;</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> Promise.resolve(<span style="color:#79c0ff">null</span>);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff7b72">return</span> openai.createCompletion({ <span style="color:#8b949e;font-style:italic">// 方法用錯修正
</span></span></span><span style="display:flex;"><span>    prompt<span style="color:#ff7b72;font-weight:bold">:</span> event.message.text,
</span></span><span style="display:flex;"><span>    model<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#34;text-davinci-003&#34;</span>, <span style="color:#8b949e;font-style:italic">// 使用 model 而非 engine
</span></span></span><span style="display:flex;"><span>    max_tokens<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">1000</span> <span style="color:#8b949e;font-style:italic">// 應用 max_tokens 而非 maxTokens
</span></span></span><span style="display:flex;"><span>  }).then((completions) =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#8b949e;font-style:italic">// 少了 data 這層結構，並要加上 trim() 去除空白
</span></span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">const</span> message <span style="color:#ff7b72;font-weight:bold">=</span> completions.data.choices[<span style="color:#a5d6ff">0</span>].text.trim();
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> client.replyMessage(event.replyToken, {
</span></span><span style="display:flex;"><span>      type<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#39;text&#39;</span>,
</span></span><span style="display:flex;"><span>      text<span style="color:#ff7b72;font-weight:bold">:</span> message
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app.listen(<span style="color:#a5d6ff">3000</span>);
</span></span><span style="display:flex;"><span>console.log(<span style="color:#a5d6ff">&#39;Linebot is running on 3000 port&#39;</span>);
</span></span></code></pre></div><p>最後再給大家看看順利溝通時的畫面：</p>
<div class="gallery-row cols-2">

<figure class="figure"><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-19.webp" width="744" height="970" alt="好吧…最後還是得靠自己處理（圖 19）" loading="lazy" decoding="async">
</figure>

<figure class="figure"><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-20.webp" width="742" height="972" alt="好吧…最後還是得靠自己處理（圖 20）" loading="lazy" decoding="async">
</figure>


</div>

<p>看到成功溝通的畫面時，筆者真的感動到快哭了，這是個能與你溝通的 AI 機器人喔！</p>
<blockquote>
<p>不過操作下來我覺得回答穩定度沒有比 ChatGPT 高，有時會出現一些奇怪的程式碼，讀者有興趣可以再做優化，本篇文章僅為參考範例。</p>
</blockquote>
<hr>
<h2 id="結論給想用-chatgpt-寫程式學程式的朋友一些建議">結論：給想用 ChatGPT 寫程式、學程式的朋友一些建議<a class="h-anchor" href="#%e7%b5%90%e8%ab%96%e7%b5%a6%e6%83%b3%e7%94%a8-chatgpt-%e5%af%ab%e7%a8%8b%e5%bc%8f%e5%ad%b8%e7%a8%8b%e5%bc%8f%e7%9a%84%e6%9c%8b%e5%8f%8b%e4%b8%80%e4%ba%9b%e5%bb%ba%e8%ad%b0" aria-label="這個段落的連結"></a></h2>
<p>可能是我運氣比較好，剛好測試到 ChatGPT 的許多 Bug，下面筆者彙整了一些遇到的「坑」給讀者參考：</p>
<ol>
<li><strong>ChatGPT 沒有最新資料</strong>：筆者在使用 ChatGPT 時，他的資料是在 2021 年截止的，也就是說他不認識新推出的套件，當套件有更新時他也無法第一時間知道。</li>
<li><strong>有些問題 ChatGPT 真的回答不出來</strong>：如果是程式邏輯問題，ChatGPT 有機會給出解答，但如果是套件相關問題，可能真的給不出解答；你一直問他也只是鬼打牆。</li>
<li><strong>似是而非的答案最可怕</strong>：ChatGPT 在上一篇（中文）跟這一篇（英文）給的答案，如果只看「邏輯」，那是正確的；但實際跑起來卻有一堆問題，不去看官方網站查證真的無法解決。</li>
</ol>
<p>會有上述問題，我覺得是因為 ChatGPT 還在學習、以及資料不夠即時；相信在未來推出新版時，能給出更正確的解答。</p>
<p>至於如何透過 ChatGPT 學程式，我的建議如下：</p>
<ol>
<li>要學習的<strong>程式語言、工具要有一定的年紀</strong>。</li>
<li>使用套件遇到錯誤時，<strong>先去官網看說明文件</strong>。</li>
<li>如果完全沒基礎，<strong>強烈建議先從書籍、課程開始學習</strong>。</li>
</ol>
<p>目前筆者把 ChatGPT 的定位放在「輔助」，適合給你方向、關鍵字、優化的建議；像是這次使用下來，雖然程式有些許錯誤，但是在「步驟、關鍵字、指令」方面的建議都是很不錯的。</p>
<p>未來筆者會出一系列使用 ChatGPT、openAI 的文章，如果你對這個議題感興趣，可以持續關注我的文章！</p>
<a class="linkcard" href="https://deanlin.net/categories/ai/">
  <span class="lc-body">
    <span class="lc-title">AI 實戰</span>
    <span class="lc-desc">實測生成式 AI 工具、Vibe Coding 與自動化流程的第一手心得，把 AI 變成每天都用得上的即戰力。</span>
    <span class="lc-site"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>林鼎淵 Dean Lin</span>
  </span>
</a>

<p><strong>想將 AI 導入自己的職場與生活嗎？歡迎<a href="https://www.books.com.tw/products/0011004216">購買筆者出版的新書</a></strong>，幫助您<strong>在 AI 的浪潮中站穩腳步，並在未來的職場競爭中佔據優勢！</strong></p>
<figure class="figure"><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/images/chatgpt-line-bot-side-project-part-2-21.webp" width="1400" height="319" alt="林鼎淵著作《ChatGPT 與 AI 繪圖效率大師（新增 Copilot、Gamma、Runway、Suno）》" loading="lazy" decoding="async">
  <figcaption><a href="https://www.books.com.tw/products/0011004216">https://www.books.com.tw/products/0011004216</a></figcaption>
</figure>

<p><strong>參考資料</strong>：</p>
<ol>
<li>用英文溝通 ChatGPT 得到的回覆：<a href="https://github.com/dean9703111/linebot-openai-chatgpt/blob/master/bug2-index.js">Github</a></li>
<li>筆者自己優化得到的解答：<a href="https://github.com/dean9703111/linebot-openai-chatgpt/blob/master/index.js">Github</a></li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>靠問 ChatGPT 寫程式，能完成 OpenAI &amp; Linebot 的 Side Project 嗎？（上）</title>
      <link>https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/</link>
      <pubDate>Wed, 25 Jan 2023 14:35:08 +0800</pubDate>
      <guid>https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>AI 實戰</category>
      <description>許多網紅都說 ChatGPT 寫程式的能力超強，不但可以解 LeeCode 還能幫你優化程式，甚至寫點小專案都不是問題，但事實真的是如此嗎？就讓筆者透過一個 Side Project 來測試看看。</description>
      <media:content url="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-og_hu_517affb4376a2a91.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<p>許多網紅都說 ChatGPT 寫程式的能力超強，不但可以解 LeeCode 還能幫你優化程式，甚至寫點小專案都不是問題，但事實真的是如此嗎？就讓筆者透過一個 Side Project 來測試看看。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-01.webp" width="1260" height="689" alt="靠問 ChatGPT 寫程式，能完成 OpenAI &amp; Linebot 的 Side Project 嗎？（上）（圖 1）" fetchpriority="high" decoding="async"></p>
<pre tabindex="0"><code>大綱

▋ 詢問 ChatGPT 實作的步驟
▋ 前置作業 1：申請 OpenAI API key
▋ 前置作業 2：取得 Line 的 Channel access token 和 Channel secret
▋ 建立 OpenAI-Linebot 的 Node.js 專案
▋ 小結：他還還努力學習中
</code></pre><h2 id="-詢問-chatgpt-實作的步驟">詢問 ChatGPT 實作的步驟<a class="h-anchor" href="#-%e8%a9%a2%e5%95%8f-chatgpt-%e5%af%a6%e4%bd%9c%e7%9a%84%e6%ad%a5%e9%a9%9f" aria-label="這個段落的連結"></a></h2>
<p>目前看起來，ChatGPT 回應給我的實作步驟可行性很高，而且每個重點都提示到了。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-02.webp" width="1074" height="738" alt="詢問 ChatGPT 實作的步驟（圖 2）" loading="lazy" decoding="async"></p>
<hr>
<h2 id="前置作業-1申請-openai-api-key">前置作業 1：申請 OpenAI API key<a class="h-anchor" href="#%e5%89%8d%e7%bd%ae%e4%bd%9c%e6%a5%ad-1%e7%94%b3%e8%ab%8b-openai-api-key" aria-label="這個段落的連結"></a></h2>
<p><strong>SETP 1</strong>：進入 OpenAI 官網：<a href="https://beta.openai.com/">https://beta.openai.com/</a></p>
<p><strong>SETP 2</strong>：註冊 &amp; 登入 OpenAI 帳號，進入首頁。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-03.webp" width="1400" height="729" alt="前置作業 1：申請 OpenAI API key（圖 3）" loading="lazy" decoding="async"></p>
<p><strong>SETP 3</strong>：點擊右上角圖像，選擇「View API keys」。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-04.webp" width="722" height="476" alt="前置作業 1：申請 OpenAI API key（圖 4）" loading="lazy" decoding="async"></p>
<p><strong>SETP 4</strong>：點擊「Create new secret key」。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-05.webp" width="1400" height="631" alt="前置作業 1：申請 OpenAI API key（圖 5）" loading="lazy" decoding="async"></p>
<p><strong>SETP 5</strong>：產生出來的 API Key 請保存好，之後你都不會再看到他了。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-06.webp" width="1400" height="584" alt="前置作業 1：申請 OpenAI API key（圖 6）" loading="lazy" decoding="async"></p>
<hr>
<h2 id="前置作業-2取得-line-的-channel-access-token-和-channel-secret">前置作業 2：取得 Line 的 Channel access token 和 Channel secret<a class="h-anchor" href="#%e5%89%8d%e7%bd%ae%e4%bd%9c%e6%a5%ad-2%e5%8f%96%e5%be%97-line-%e7%9a%84-channel-access-token-%e5%92%8c-channel-secret" aria-label="這個段落的連結"></a></h2>
<p>因為步驟比較複雜，所以我有詢問一下 ChatGPT ：</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-07.webp" width="1085" height="656" alt="前置作業 2：取得 Line 的 Channel access token 和 Channel secret（圖 7）" loading="lazy" decoding="async"></p>
<p><strong>SETP 1</strong>：登入開發者平台，網址：<a href="https://developers.line.biz/zh-hant/">https://developers.line.biz/zh-hant/</a> 。</p>
<p><strong>SETP 2</strong>：建立一個 provider，名字自取。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-08.webp" width="1400" height="730" alt="前置作業 2：取得 Line 的 Channel access token 和 Channel secret（圖 8）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-09.webp" width="878" height="489" alt="前置作業 2：取得 Line 的 Channel access token 和 Channel secret（圖 9）" loading="lazy" decoding="async"></p>
<p><strong>SETP 3</strong>：選擇「Create a Message API channel」，我們要做一個聊天機器人。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-10.webp" width="1400" height="668" alt="前置作業 2：取得 Line 的 Channel access token 和 Channel secret（圖 10）" loading="lazy" decoding="async"></p>
<p>接下來填寫一些必填資訊：</p>
<ul>
<li><strong>Company or owner&rsquo;s country or region</strong>：Taiwan</li>
<li><strong>Channel name</strong>：ChatGPT bot（自由填寫）</li>
<li><strong>Channel description</strong>：ChatGPT bot（自由填寫）</li>
<li><strong>Category</strong>：公眾人物、專業人士（自由填寫）</li>
<li><strong>Subcategory</strong>：IT、電腦（自由填寫）</li>
</ul>
<p><strong>SETP 4</strong>：最下面兩個同意事項要打勾才能按下「Create」按鈕。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-11.webp" width="869" height="289" alt="前置作業 2：取得 Line 的 Channel access token 和 Channel secret（圖 11）" loading="lazy" decoding="async"></p>
<p>最後會讓你確認一下填寫的細節，還有一些規則提醒。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-12.webp" width="901" height="548" alt="前置作業 2：取得 Line 的 Channel access token 和 Channel secret（圖 12）" loading="lazy" decoding="async"></p>
<p><strong>SETP 5</strong>：在 Basic settings 取得 Channel secret（這邊 ChatGPT 說錯成 General settings，不過大體意思能理解）。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-13.webp" width="1332" height="543" alt="前置作業 2：取得 Line 的 Channel access token 和 Channel secret（圖 13）" loading="lazy" decoding="async"></p>
<p><strong>SETP 6</strong>：在 Messaging API 取得 Channel access token。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-14.webp" width="1301" height="641" alt="前置作業 2：取得 Line 的 Channel access token 和 Channel secret（圖 14）" loading="lazy" decoding="async"></p>
<blockquote>
<p><strong>注意</strong>：<br>Channel access token 是用來驗證和保護機器人與 LINE Platform 之間的通訊，因此請勿將它公開給任何人。<br>Channel secret 則是用來驗證 Webhook 事件的簽章。</p>
</blockquote>
<hr>
<h2 id="建立-openai-linebot-的-nodejs-專案">建立 OpenAI-Linebot 的 Node.js 專案<a class="h-anchor" href="#%e5%bb%ba%e7%ab%8b-openai-linebot-%e7%9a%84-nodejs-%e5%b0%88%e6%a1%88" aria-label="這個段落的連結"></a></h2>
<p>下面的步驟，我是透過詢問 ChatGPT 所得到的：「接下來要如何建立一個 Node.js 專案，並安裝&quot;openai&quot; 和 &ldquo;@line/bot-sdk&rdquo; 等套件呢？有相關指令與程式範例嗎？」</p>
<p><strong>SETP 1</strong>：建立一個新的專案目錄，並在終端機中進入該目錄。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir myproject
</span></span><span style="display:flex;"><span>cd myproject
</span></span></code></pre></div><p><strong>SETP 2</strong>：建立一個 package.json 檔案，並設定專案的相關資訊。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>npm init
</span></span></code></pre></div><p><strong>SETP 3</strong>：安裝 &ldquo;openai&rdquo;、&quot;@line/bot-sdk&quot;、&ldquo;express&quot;套件（這邊原本是建議裝 line-bot-sdk 這個套件，但因為無法使用，所以請 ChatGPT 重選了一次）。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>npm install openai @line/bot-sdk express
</span></span></code></pre></div><blockquote>
<p>注意！在使用上面的指令前，需要先安裝 Node.js 和 npm。</p>
</blockquote>
<p><strong>SETP 4</strong>：建立一個新的檔案放程式碼。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>touch index.js
</span></span></code></pre></div><p><strong>SETP 5</strong>：在 index.js 中引用所需的套件，並設定 OpenAI 的 API key、Linebot 的 channelAccessToken、channelSecret。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#ff7b72">const</span> openai <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#39;openai&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> line <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#39;@line/bot-sdk&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>openai.apiKey <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">&#34;YOUR_OPENAI_API_KEY&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> config <span style="color:#ff7b72;font-weight:bold">=</span> {
</span></span><span style="display:flex;"><span>  channelAccessToken<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#39;YOUR_CHANNEL_ACCESS_TOKEN&#39;</span>,
</span></span><span style="display:flex;"><span>  channelSecret<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#39;YOUR_CHANNEL_SECRET&#39;</span>
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> client <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#ff7b72">new</span> line.Client(config);
</span></span></code></pre></div><p><strong>SETP 6</strong>：在 index.js 中建立一個 HTTP server 並設定 line 的 webhook。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#ff7b72">const</span> express <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#39;express&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> app <span style="color:#ff7b72;font-weight:bold">=</span> express();
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">const</span> port <span style="color:#ff7b72;font-weight:bold">=</span> <span style="color:#a5d6ff">3000</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app.post(<span style="color:#a5d6ff">&#39;/webhook&#39;</span>, line.middleware(config), (req, res) =&gt; {
</span></span><span style="display:flex;"><span>  Promise
</span></span><span style="display:flex;"><span>    .all(req.body.events.map(handleEvent))
</span></span><span style="display:flex;"><span>    .then((result) =&gt; res.json(result))
</span></span><span style="display:flex;"><span>    .<span style="color:#ff7b72">catch</span>((err) =&gt; {
</span></span><span style="display:flex;"><span>      console.error(err);
</span></span><span style="display:flex;"><span>      res.status(<span style="color:#a5d6ff">500</span>).end();
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app.listen(port, () =&gt; {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">`app is running on port </span><span style="color:#a5d6ff">${</span>port<span style="color:#a5d6ff">}</span><span style="color:#a5d6ff">`</span>);
</span></span><span style="display:flex;"><span>})
</span></span></code></pre></div><p><strong>SETP 7</strong>：在 index.js 中建立一個事件處理函式，當使用者發送訊息時，使用 OpenAI API 將訊息傳到指定的語言模型處理，並將回應的結果傳回給使用者。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#ff7b72">function</span> handleEvent (event) {
</span></span><span style="display:flex;"><span>  <span style="color:#ff7b72">if</span> (event.type <span style="color:#ff7b72;font-weight:bold">!==</span> <span style="color:#a5d6ff">&#39;message&#39;</span> <span style="color:#ff7b72;font-weight:bold">||</span> event.message.type <span style="color:#ff7b72;font-weight:bold">!==</span> <span style="color:#a5d6ff">&#39;text&#39;</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> Promise.resolve(<span style="color:#79c0ff">null</span>);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  <span style="color:#ff7b72">return</span> openai.Completion.create({
</span></span><span style="display:flex;"><span>    engine<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#34;text-davinci-002&#34;</span>,
</span></span><span style="display:flex;"><span>    prompt<span style="color:#ff7b72;font-weight:bold">:</span> event.message.text,
</span></span><span style="display:flex;"><span>  }).then(response =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#ff7b72">return</span> client.replyMessage(event.replyToken, {
</span></span><span style="display:flex;"><span>      type<span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#39;text&#39;</span>,
</span></span><span style="display:flex;"><span>      text<span style="color:#ff7b72;font-weight:bold">:</span> response.choices[<span style="color:#a5d6ff">0</span>].text
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>SETP 8</strong>：最後啟動伺服器 <code>node index.js</code></p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-15.webp" width="1270" height="202" alt="建立 OpenAI-Linebot 的 Node.js 專案（圖 15）" loading="lazy" decoding="async"></p>
<p>喔喔喔！居然沒有報錯！！！<br>之後可以請 ChatGPT 幫我完成 Side Project 了嗎？</p>
<blockquote>
<p><strong>小提醒</strong>：程式能啟動跟能順利執行是兩件事。</p>
</blockquote>
<hr>
<h2 id="小結他還在努力學習中">小結：他還在努力學習中<a class="h-anchor" href="#%e5%b0%8f%e7%b5%90%e4%bb%96%e9%82%84%e5%9c%a8%e5%8a%aa%e5%8a%9b%e5%ad%b8%e7%bf%92%e4%b8%ad" aria-label="這個段落的連結"></a></h2>
<p>其實過程並沒有想像中順利，上面放的步驟已經是多次優化後得到的答案，下面筆者放幾個請 ChatGPT 優化的片段。</p>
<p><strong>錯誤 1</strong>： 我按造步驟執行後，會噴錯誤：「TypeError: line.Client is not a constructor」</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-16.webp" width="1088" height="749" alt="小結：他還在努力學習中（圖 16）" loading="lazy" decoding="async"></p>
<p><strong>錯誤 2</strong>：我調整後，會噴錯誤：「TypeError: Cannot read properties of undefined (reading &lsquo;validateSignature&rsquo;)」</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-17.webp" width="1091" height="682" alt="小結：他還在努力學習中（圖 17）" loading="lazy" decoding="async"></p>
<p>其實還有其他錯誤，只是這兩個最嚴重，所以筆者單獨拿出來說一下。</p>
<p>對初學者而言而言，他們可能會覺得是程式哪裡寫錯了，只要修改一下就好；但實際上，真正的問題是<strong> ChatGPT 一開始推薦安裝的套件「line-bot-sdk」就是有問題的</strong>。</p>
<p>這邊放個截圖給大家看一下，<strong>這款套件已經有 7 年多沒有更新，而且幾乎沒有下載量！</strong>如果是缺乏經驗的開發者，應該會在這裡卡很久。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-18.webp" width="1400" height="707" alt="小結：他還在努力學習中（圖 18）" loading="lazy" decoding="async"></p>
<p>後來我請他重新推薦，ChatGPT 才給了比較合理的套件，最後我請他改用「@line/bot-sdk」重寫一遍才得到上面的結果。</p>
<p><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-19.webp" width="1075" height="519" alt="小結：他還在努力學習中（圖 19）" loading="lazy" decoding="async"></p>
<p>不知道這篇文章會不會勸退一些使用者？</p>
<p>其實 ChatGPT 的問題並不只這些，<a href="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-2/">下一篇文章</a>我會帶大家把後面「啟動 server 並在 Line 開發者平台設定 webhook 的網址、測試機器人是否能正確回應使用者的訊息」等步驟走完，希望筆者踩過的坑能讓讀者日後使用時少走點彎路。</p>
<blockquote>
<p>本次 ChatGPT 回應的完整程式請參考筆者的 <a href="https://github.com/dean9703111/linebot-openai-chatgpt/blob/master/bug-index.js">Github</a></p>
</blockquote>
<p>未來筆者會出一系列使用 ChatGPT、openAI 的文章，如果你對這個議題感興趣，可以持續關注我的文章！</p>
<a class="linkcard" href="https://deanlin.net/categories/ai/">
  <span class="lc-body">
    <span class="lc-title">AI 實戰</span>
    <span class="lc-desc">實測生成式 AI 工具、Vibe Coding 與自動化流程的第一手心得，把 AI 變成每天都用得上的即戰力。</span>
    <span class="lc-site"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>林鼎淵 Dean Lin</span>
  </span>
</a>

<p><strong>想將 AI 導入自己的職場與生活嗎？歡迎<a href="https://www.books.com.tw/products/0011004216">購買筆者出版的新書</a></strong>，幫助您<strong>在 AI 的浪潮中站穩腳步，並在未來的職場競爭中佔據優勢！</strong></p>
<figure class="figure"><img src="https://deanlin.net/blog/202301/chatgpt-line-bot-side-project-part-1/images/chatgpt-line-bot-side-project-part-1-20.webp" width="1400" height="319" alt="林鼎淵著作《ChatGPT 與 AI 繪圖效率大師（新增 Copilot、Gamma、Runway、Suno）》" loading="lazy" decoding="async">
  <figcaption><a href="https://www.books.com.tw/products/0011004216">https://www.books.com.tw/products/0011004216</a></figcaption>
</figure>

]]></content:encoded>
    </item>
    <item>
      <title>讓Line機器人變成你的小秘書</title>
      <link>https://deanlin.net/blog/202006/line-bot-personal-assistant/</link>
      <pubDate>Wed, 10 Jun 2020 12:13:46 +0800</pubDate>
      <guid>https://deanlin.net/blog/202006/line-bot-personal-assistant/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>技術教學</category>
      <description>機器人的秘書還不夠誘惑嗎ＸＤ</description>
      <media:content url="https://deanlin.net/blog/202006/line-bot-personal-assistant/images/line-bot-personal-assistant-og_hu_2dae16f1f3dfcd3f.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<blockquote>
<p>為什麼撰寫這篇文章</p>
</blockquote>
<p>在<a href="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/">上一篇</a>文章已經介紹了Google App Script如何串接Line Message Api的應用，在這裡我將延續之前的議題，讓Line機器人變成你的小秘書</p>
<blockquote>
<p>文章目標</p>
</blockquote>
<ol>
<li>使用Google Sheet裡面Script的功能</li>
<li>使用簡單的SQL語法抓出Google Sheet中你需要的資訊</li>
</ol>
<blockquote>
<p>本文章使用到的技術：</p>
</blockquote>
<ol>
<li>Google App Script : 這次著重在執行SQL語法</li>
<li>Google Sheet : 會把它當成讀取/寫入的資料庫</li>
</ol>
<h2 id="step-1-結合google-sheet的衍生應用">STEP 1: 結合Google Sheet的衍生應用<a class="h-anchor" href="#step-1-%e7%b5%90%e5%90%88google-sheet%e7%9a%84%e8%a1%8d%e7%94%9f%e6%87%89%e7%94%a8" aria-label="這個段落的連結"></a></h2>
<blockquote>
<p>Google App Script功能很多，但能做到什麼地步就看個人的想像能力，接下來我提供的只是一條思路，如果大家想到有趣的應用歡迎下方留言</p>
</blockquote>
<p>如果大家平常有使用Google sheet當成工作記錄習慣的話，你可以嘗試看看這個應用</p>
<p>這裡我先創建一個Google Sheet，裡面建立一些清單(<a href="https://docs.google.com/spreadsheets/d/1ZdmsEkS27VWR6HF42_aka5rrtgu31saZoUupOD8Xx6s/edit?usp=sharing">你可以直接複製我的</a>)：</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-personal-assistant/images/line-bot-personal-assistant-01.webp" width="1400" height="591" alt="STEP 1: 結合Google Sheet的衍生應用（圖 1）" fetchpriority="high" decoding="async"></p>
<p>接著建立Google Sheet的Script</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-personal-assistant/images/line-bot-personal-assistant-02.webp" width="1400" height="811" alt="STEP 1: 結合Google Sheet的衍生應用（圖 2）" loading="lazy" decoding="async"></p>
<p>將以下程式複製貼上，如果您願意可以自由更改，記得將<a href="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/">上一篇</a>取得的line token放上去喔</p>
<pre tabindex="0"><code>var ss = SpreadsheetApp.getActiveSpreadsheet()//抓取這張excel
function doPost (e) {
    var msg = JSON.parse(e.postData.contents);
    // 取出 replayToken 和發送的訊息文字
    var replyToken = msg.events[0].replyToken;
    var userMessage = msg.events[0].message.text;

    if (userMessage.indexOf(&#34;未完成&#34;) &gt; -1) {//分析傳遞字串確認是否有“未完成”
        // QUERY(目標文件及範圍,SQL語法)
        // 尋找sheet1範圍A2到C100裡面A跟B欄位的資料且C欄位為FALSE
        var formulaToUse = &#39;=QUERY(Sheet1!A2:C100,&#34;SELECT A,B WHERE C = FALSE&#34;)&#39;
        var result = query(formulaToUse)

        var userMessage = &#39;未完成文件如下：\n&#39;;//單純的文字組成
        result.forEach(row =&gt; {
            userMessage = userMessage + row[0] + &#39;:&#39; + row[1] + &#39;\n&#39;
        })
        return sendLineMsg(userMessage, replyToken);
    }
    if (userMessage.indexOf(&#34;已完成&#34;) &gt; -1) {//分析傳遞字串確認是否有“已完成”
        var formulaToUse = &#39;=QUERY(Sheet1!A2:C100,&#34;SELECT A,B WHERE C = TRUE&#34;)&#39;
        var result = query(formulaToUse)
        var userMessage = &#39;已完成文件如下：\n&#39;;
        result.forEach(row =&gt; {
            userMessage = userMessage + row[0] + &#39;:&#39; + row[1] + &#39;\n&#39;
        })
        return sendLineMsg(userMessage, replyToken);
    }
    if (userMessage.indexOf(&#34;功能&#34;) &gt; -1) {//這是列出你有提供功能的列表
        return sendLineMsg(&#39;朕不給的你不能搶ㄎㄎ\n• 未完成 ：列出excel未完成清單\n• 已完成 ：列出excel已完成清單&#39;, replyToken);
    }
}
function query (request) { //執行SQL語法的地方
    var sheet = ss.insertSheet(); //先插入一張新的sheet(也許有更好的做法，如果有請告訴我ＱＱ)
    sheet.getActiveRange().setFormula(request); //執行SQL
    var result = sheet.getDataRange().getValues(); //把整張表抓下來
    ss.deleteSheet(sheet); //把sheet刪除
    Logger.log(result);//可透過log來看輸出的資訊(上方的View Logs)
    return result; //回傳結果
}
function sendLineMsg (Message, replyToken) {
    var CHANNEL_ACCESS_TOKEN = &#39;你的 Channel access token&#39;;

    var url = &#39;https://api.line.me/v2/bot/message/reply&#39;;
    UrlFetchApp.fetch(url, {
        &#39;headers&#39;: {
            &#39;Content-Type&#39;: &#39;application/json; charset=UTF-8&#39;,
            &#39;Authorization&#39;: &#39;Bearer &#39; + CHANNEL_ACCESS_TOKEN,
        },
        &#39;method&#39;: &#39;post&#39;,
        &#39;payload&#39;: JSON.stringify({
            &#39;replyToken&#39;: replyToken,
            &#39;messages&#39;: [{
                &#39;type&#39;: &#39;text&#39;,
                &#39;text&#39;: Message,
            }],
        }),
    });
}
</code></pre><p class="code-source">原始碼：<a href="https://gist.github.com/dean9703111/8f6d1e06b079ae3061d450d459cedc2c" rel="noopener">line_secretary.gs</a>（GitHub Gist）</p>
<p>接下來要將這個程式發布（如果有授權相關問題必須都接受才會通過）</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-personal-assistant/images/line-bot-personal-assistant-03.webp" width="998" height="408" alt="STEP 1: 結合Google Sheet的衍生應用（圖 3）" loading="lazy" decoding="async"></p>
<p>Project version記得每次都要選擇New(否則不會更新)，並且要允許任何人可以存取這隻app，不然你的程式無法被line機器人執行</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-personal-assistant/images/line-bot-personal-assistant-04.webp" width="892" height="804" alt="STEP 1: 結合Google Sheet的衍生應用（圖 4）" loading="lazy" decoding="async"></p>
<p>接下來複製你這串web app URL給LINE Message Api使用</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-personal-assistant/images/line-bot-personal-assistant-05.webp" width="892" height="534" alt="STEP 1: 結合Google Sheet的衍生應用（圖 5）" loading="lazy" decoding="async"></p>
<p>貼到webhook URL上面後按下Save</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-personal-assistant/images/line-bot-personal-assistant-06.webp" width="1400" height="698" alt="STEP 1: 結合Google Sheet的衍生應用（圖 6）" loading="lazy" decoding="async"></p>
<h2 id="step-2--驗證串接成功">STEP 2 : 驗證串接成功<a class="h-anchor" href="#step-2--%e9%a9%97%e8%ad%89%e4%b8%b2%e6%8e%a5%e6%88%90%e5%8a%9f" aria-label="這個段落的連結"></a></h2>
<p>打開你的LINE就可以輸入下面三種文字，機器人就會做相對應的回覆喔！</p>
<ol>
<li>功能</li>
<li>未完成</li>
<li>已完成</li>
</ol>
<p><img src="https://deanlin.net/blog/202006/line-bot-personal-assistant/images/line-bot-personal-assistant-07.webp" width="748" height="1140" alt="STEP 2 : 驗證串接成功（圖 7）" loading="lazy" decoding="async"></p>
<p>希望大家喜歡這篇文章的應用～</p>
]]></content:encoded>
    </item>
    <item>
      <title>用Google App Script打造打造自己的lINE機器人</title>
      <link>https://deanlin.net/blog/202006/line-bot-with-google-apps-script/</link>
      <pubDate>Wed, 10 Jun 2020 12:12:04 +0800</pubDate>
      <guid>https://deanlin.net/blog/202006/line-bot-with-google-apps-script/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>技術教學</category>
      <description>來打造一個回聲狗吧～</description>
      <media:content url="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-og_hu_5aca1942c5c55728.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<blockquote>
<p>為什麼撰寫這篇文章</p>
</blockquote>
<p>Google App Script在以前我就非常的喜愛，也曾用他來當我專案後台登入的api來使用，搭配上Google Sheet，你簡直獲得了免費資料庫(不過他執行的速度就…反正就免費的速度XD)</p>
<p>但為了讓技術經過這段日子獲得更多提升，我想在原先資料庫的應用上加點料，比如說串接機器人，讓機器人對你定期提醒</p>
<p>本文章僅僅是示範最簡單的應用層面，實際上應該有非常多的應用等待大家去發掘</p>
<blockquote>
<p>文章目標</p>
</blockquote>
<ol>
<li>了解Google App Script，可撰寫簡單api並附帶參數</li>
<li>Google App Script串接Line機器人，讓你可以自由決定使用功能</li>
</ol>
<blockquote>
<p>本文章使用到的技術：</p>
</blockquote>
<ol>
<li>Google App Script : 撰寫你想要執行的邏輯</li>
<li>LINE developers : 打造自己的lINE機器人</li>
</ol>
<h2 id="setp-1-建立-line-messaging-api">SETP 1: 建立 LINE Messaging API<a class="h-anchor" href="#setp-1-%e5%bb%ba%e7%ab%8b-line-messaging-api" aria-label="這個段落的連結"></a></h2>
<p>我們要先在<a href="https://developers.line.biz/zh-hant/">這裡申請到line</a>發送訊息所需要的token</p>
<p>除了Channel type要寫Messaging API外其他就自由發揮，反正你填錯或是漏填LINE會逼著你填完</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-01.webp" width="1400" height="682" alt="SETP 1: 建立 LINE Messaging API（圖 1）" fetchpriority="high" decoding="async"></p>
<p>新增完成後在Messaging Api裡面的basic id就是這個機器人在line的id</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-02.webp" width="1400" height="905" alt="SETP 1: 建立 LINE Messaging API（圖 2）" loading="lazy" decoding="async"></p>
<p>你就能在line裡面透過id找到他惹</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-03.webp" width="624" height="810" alt="SETP 1: 建立 LINE Messaging API（圖 3）" loading="lazy" decoding="async"></p>
<p>除了id之外最重要的就是token，這個也是在Messaging Api裡面的Channel access token</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-04.webp" width="1400" height="668" alt="SETP 1: 建立 LINE Messaging API（圖 4）" loading="lazy" decoding="async"></p>
<p>另外我們不需要Greeting message、Auto response的功能</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-05.webp" width="1400" height="890" alt="SETP 1: 建立 LINE Messaging API（圖 5）" loading="lazy" decoding="async"></p>
<h2 id="step-2--建立-google-apps-script-接收-line-訊息">STEP 2 : 建立 Google Apps Script 接收 LINE 訊息<a class="h-anchor" href="#step-2--%e5%bb%ba%e7%ab%8b-google-apps-script-%e6%8e%a5%e6%94%b6-line-%e8%a8%8a%e6%81%af" aria-label="這個段落的連結"></a></h2>
<p>你可以在<a href="https://www.google.com/script/start/">這裡開始你的Google App Script</a>的故事 ，點擊Start Scripting，開啟一個Google App Script的專案吧</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-06.webp" width="1400" height="944" alt="STEP 2 : 建立 Google Apps Script 接收 LINE 訊息（圖 6）" loading="lazy" decoding="async"></p>
<p>將以下程式複製貼上，如果您願意可以自由更改，記得將剛剛取得的line token放上去喔</p>
<pre tabindex="0"><code>function doPost (e) { //凡事使用post method皆要通過這個function 

  var CHANNEL_ACCESS_TOKEN = &#39;你的 Channel access token&#39;;
  var msg = JSON.parse(e.postData.contents);

  // 取出 replayToken 和發送的訊息文字
  var replyToken = msg.events[0].replyToken;
  var userMessage = msg.events[0].message.text;

  if (typeof replyToken === &#39;undefined&#39;) {
    return;
  }

  var url = &#39;https://api.line.me/v2/bot/message/reply&#39;;
  UrlFetchApp.fetch(url, {
    &#39;headers&#39;: {
      &#39;Content-Type&#39;: &#39;application/json; charset=UTF-8&#39;,
      &#39;Authorization&#39;: &#39;Bearer &#39; + CHANNEL_ACCESS_TOKEN,
    },
    &#39;method&#39;: &#39;post&#39;,
    &#39;payload&#39;: JSON.stringify({
      &#39;replyToken&#39;: replyToken,
      &#39;messages&#39;: [{
        &#39;type&#39;: &#39;text&#39;, // 格式為文字，line可以傳送多種個格式(carousel、image)，有興趣的可以自己研究
        &#39;text&#39;: userMessage, //你目標傳遞的訊息
      }],
    }),
  });
}
</code></pre><p class="code-source">原始碼：<a href="https://gist.github.com/dean9703111/7b90f26418375ed32aec1370a9673059" rel="noopener">code.gs</a>（GitHub Gist）</p>
<p>接下來要將這個程式發布（如果有授權相關問題必須都接受才會通過）</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-07.webp" width="1014" height="396" alt="STEP 2 : 建立 Google Apps Script 接收 LINE 訊息（圖 7）" loading="lazy" decoding="async"></p>
<p>Project version記得每次都要選擇New(否則不會更新)，並且要允許任何人可以存取這隻app，不然你的程式無法被line機器人執行</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-08.webp" width="892" height="804" alt="STEP 2 : 建立 Google Apps Script 接收 LINE 訊息（圖 8）" loading="lazy" decoding="async"></p>
<p>接下來複製你這串web app URL給LINE Message Api使用</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-09.webp" width="892" height="534" alt="STEP 2 : 建立 Google Apps Script 接收 LINE 訊息（圖 9）" loading="lazy" decoding="async"></p>
<p>貼到webhook URL上面後按下Save</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-10.webp" width="1400" height="698" alt="STEP 2 : 建立 Google Apps Script 接收 LINE 訊息（圖 10）" loading="lazy" decoding="async"></p>
<h2 id="step-3-驗證串接成功">STEP 3: 驗證串接成功<a class="h-anchor" href="#step-3-%e9%a9%97%e8%ad%89%e4%b8%b2%e6%8e%a5%e6%88%90%e5%8a%9f" aria-label="這個段落的連結"></a></h2>
<p>打開你的LINE就可以測試功能是否正常嚕～如果你是按照我的程式碼複製貼上，那他現在應該是回聲狗的功能XD</p>
<p><img src="https://deanlin.net/blog/202006/line-bot-with-google-apps-script/images/line-bot-with-google-apps-script-11.webp" width="748" height="886" alt="STEP 3: 驗證串接成功（圖 11）" loading="lazy" decoding="async"></p>
<p><strong>今天的教學就到這裡了～串接Google Sheet的部分我會放到<a href="https://deanlin.net/blog/202006/line-bot-personal-assistant/">下一篇文章</a>，歡迎有興趣的人來觀看喔！</strong></p>
<p>參考資源：<a href="https://www.oxxostudio.tw/articles/201805/backend-apps-script.html">簡易後端實作 ( Google Apps Script )</a></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
