<?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>ChatGPT LINE Bot 實作｜林鼎淵 Dean Lin</title>
    <link>https://deanlin.net/series/chatgpt-line-bot/</link>
    <image><url>https://deanlin.net/images/author_hu_aa256fc934e9a932.jpg</url><title>ChatGPT LINE Bot 實作｜林鼎淵 Dean Lin</title><link>https://deanlin.net/series/chatgpt-line-bot/</link><width>144</width><height>144</height></image>
    <description>完全靠問 ChatGPT 寫程式，看能不能完成串接 OpenAI 的 LINE Bot Side Project。</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/series/chatgpt-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>
  </channel>
</rss>
