陳子傑
  • NEW!
    NEW!  Connect Ideas Across Notes
    Save time and share insights. With Paragraph Citation, you can quote others’ work with source info built in. If someone cites your note, you’ll see a card showing where it’s used—bringing notes closer together.
    Got it
      • Create new note
      • Create a note from template
        • Sharing URL Link copied
        • /edit
        • View mode
          • Edit mode
          • View mode
          • Book mode
          • Slide mode
          Edit mode View mode Book mode Slide mode
        • Customize slides
        • Note Permission
        • Read
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Write
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invite by email
        Invitee

        This note has no invitees

      • Publish Note

        Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

        Your note will be visible on your profile and discoverable by anyone.
        Your note is now live.
        This note is visible on your profile and discoverable online.
        Everyone on the web can find and read all notes of this public team.

        Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Explore these features while you wait
        Complete general settings
        Bookmark and like published notes
        Write a few more notes
        Complete general settings
        Write a few more notes
        See published notes
        Unpublish note
        Please check the box to agree to the Community Guidelines.
        View profile
      • Commenting
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
        • Everyone
      • Suggest edit
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
      • Emoji Reply
      • Enable
      • Versions and GitHub Sync
      • Note settings
      • Note Insights New
      • Engagement control
      • Make a copy
      • Transfer ownership
      • Delete this note
      • Save as template
      • Insert from template
      • Import from
        • Dropbox
        • Google Drive
        • Gist
        • Clipboard
      • Export to
        • Dropbox
        • Google Drive
        • Gist
      • Download
        • Markdown
        • HTML
        • Raw HTML
    Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
    Create Create new note Create a note from template
    Menu
    Options
    Engagement control Make a copy Transfer ownership Delete this note
    Import from
    Dropbox Google Drive Gist Clipboard
    Export to
    Dropbox Google Drive Gist
    Download
    Markdown HTML Raw HTML
    Back
    Sharing URL Link copied
    /edit
    View mode
    • Edit mode
    • View mode
    • Book mode
    • Slide mode
    Edit mode View mode Book mode Slide mode
    Customize slides
    Note Permission
    Read
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Write
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Linebot 進階 - 小專案課程3 記憶傳承人 ## 建議事項 - 請至少對第一堂社課 + ngrok範例影片有一定印象 - 本地端運行 + ngrok : [Linebot 開發 – 測試環境建立以快速測試](/M__0hsU6SSq0IWTxOOffLg) ## 你可以先開的畫面 - [今天Fork的專案](https://github.com/bsbacon0966/GDG_linebot_W3) - [Firebase](https://firebase.google.com/) ## 今日課程 目標:使用 Linebot 結合 Firebase 使你的機器人具有記憶效果 - 申請Firebase憑證 - 透過呼叫collection->document來進行讀、寫資料 - 一些設計Linebot可以有的小技巧 >[!Warning]**此課程的調性** >Linebot + Firebase,之中的程式呼叫相對複雜很多,很可能一般0基礎開發的學員很難理解,請如果真的不知道該怎麼辦,呼叫助教或是ChatGPT來協助你 --- ## 第0步 : 為何要結合Firebase 如果你有跟上前兩週的課程內容,應該會發現一件事: **LineBot 自身並沒有記憶能力**,而且我們現階段做的作品都是程式判斷要回應甚麼而已,每一次的訊息事件,對 Bot 來說都是「獨立的」。 所以我們可以透過Firebase,來讓我們的Linebot有一個"集中資料庫",儲存使用者輸入的資料。 --- ## 第1步 : 申請Firebase憑證 - 搜尋[Firebase](https://firebase.google.com/),並進到此畫面,點選下方"Get Started in Console" <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/rkb4K5Dyee.png" style="width: 100%; border: 2px solid black; padding: 5px;" /> </div> - 點選"建立Firebase專案" <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BJeqF5DJll.png" style="width: 75%; border: 2px solid black; padding: 5px;" /> </div> - 輸入專案名稱,取隨意名字都可以,輸入完後點選"繼續" <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/rkGW5qv1ll.png" style="width: 75%; border: 2px solid black; padding: 5px;" /> </div> - 這裡他會要你選擇"Google Analytics"帳號,點選"Default"即可,**只要你沒有在此寫你的信用卡帳戶,使用Firebase都是免費的** <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BySQq5P1xl.png" style="width: 75%; border: 2px solid black; padding: 5px;" /> </div> - 進入到專案後,點左側的 "建構->Firestore Database" <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/SkUnq9PJxl.png" style="width: 75%; border: 2px solid black; padding: 5px;" /> </div> - 點選"建立資料庫",讓他架設資料庫 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/B17eo5wJll.png" style="width: 75%; border: 2px solid black; padding: 5px;" /> </div> - 進入後,他會詢問你"安全性規則",先幫我點選"測試版模式"啟動他 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/ryt7j9wkle.png" style="width: 75%; border: 2px solid black; padding: 5px;" /> </div> - 建立完後,看向左上角的"專案總覽 -> 專案設定" <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BJi0oqwkel.png" style="width: 75%; border: 2px solid black; padding: 5px;" /> </div> - 看到"專案設定 -> 服務帳戶",往下滑,直到看到"產生新的私密金鑰" <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/r1oZhcwkxe.png" style="width: 75%; border: 2px solid black; padding: 5px;" /> </div> <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BJUG2qvygl.png" style="width: 75%; border: 2px solid black; padding: 5px;" /> </div> - 這時,他會下載一個.json的檔案,**請將其改名成"firebase_key.json"**,這個就是連線到Firebase的憑證 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/Hy3_hcD1eg.png" style="width: 60%; border: 2px solid black; padding: 5px;" /> </div> --- ## 第2步 : 與程式專案結合(這裡以Codespace作範例) >[!Important]Codespace可以做的,不代表本地端可以 >研究後確認,如果你在Codespce運行```python app.py``` >他會給你一個選項為"設為公用",這樣他給你的"轉送網址"貼到Linebot的Webhook URL使可以運行的 >如果你使本地端運行程式碼,請回到上方看ngrok的架設 >![image](https://hackmd.io/_uploads/BkdteoP1el.png) ### 2-0 今天的範例Code 請對[此專案](https://github.com/bsbacon0966/GDG_linebot_W3)進行fork,此檔案與第一周的範例程式碼相近。 ### 2-1 基本設置 - 將剛剛下載的json憑證貼上 - 將原有的```.env.example```改名成```.env``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/H1dw-jDylg.png" style="width: 60%; border: 2px solid black; padding: 5px;" /> </div> - 將.env檔案中的```LINE_TOKEN```和```LINE_SECRET```貼上你Linebot的Token與Secret資訊 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/ByvTWjDJxe.png" style="width: 100%; border: 2px solid black; padding: 5px;" /> </div> - 將.gitignore中,新增```firebase_key.json```,這樣等等push回到Github上時,**==你的json憑證不會跟著上傳到公開場所==** <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/r1PJQjP1eg.png" style="width: 80%; border: 2px solid black; padding: 5px;" /> </div> - 在終端機輸入```python app.py```,如果剛剛輸入的.env順利的話,他就會運行 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/HJdwMjwJlg.png" style="width: 70%; border: 2px solid black; padding: 5px;" /> </div> - 運行時,他會跳通知說"可以設為公開",請點選"公開" <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BypSQiv1le.png" style="width: 70%; border: 2px solid black; padding: 5px;" /> </div> - 點選後,你會看到"轉送位址",你可以將其複製下來,並貼到Linebot -> Webhook URL,就可以直接測試你新寫好的Linebot程式碼了! <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/B1NKQswklg.png" style="width: 100%; border: 2px solid black; padding: 5px;" /> </div> ## 第3步 : 先使用看看Firebase ```python= # Firebase 初始化 ###################################################### cred = credentials.Certificate("firebase_key.json") # 放你的金鑰路徑 firebase_admin.initialize_app(cred) db = firestore.client() ###################################################### ``` ```python= # 設置一個事件處理器來處理 TextMessage 事件 @handler.add(MessageEvent, message=TextMessage) def handle_message(event: Event): if event.message.type == "text": user_message = event.message.text # 使用者的訊息 app.logger.info(f"收到的訊息: {user_message}") # 存到 Firestore(範例結構: GDG/W3/records/{儲存訊息}) ################################################################### reply_text = "你說了:" + user_message line_bot_api.reply_message(reply_token, TextSendMessage(text=reply_text)) doc_address = db.collection("GDG").document("W3") doc = doc_address.get() if doc.exists: doc_data = doc.to_dict() history = doc_data.get("record", []) else: history = [] print(history) history.append(reply_text) doc_address.set({"record": history}) ################################################################### ``` 將程式碼貼上後,運行```python app.py```,即可開始運行! 回到剛剛創建的Firebase,如果有看到下圖的格式,那恭喜你的linebot有了資料庫。 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/SymsoFOyeg.png" style="width: 100%; border: 2px solid black; padding: 5px;" /> </div> ## 第4步 : 看懂Firebase的程式碼 ### 4-1 Firebase結構 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BJS3hFuJex.png" style="width: 80%; border: 2px solid black; padding: 5px;" /> </div> >[!Note]通俗的記法 > Collection = 抽屜的標籤 > Document = 當前抽屜的文件名稱 > Document的標籤層 = 當前文件中,標註的變數名稱與資料 則我們如果要儲存資料,那我們就要: - 先導引到目標Document - 讀取Document中,目標變數名稱 - 將資料轉成.dict,讓Python得以看懂 ``` python= doc_address = db.collection("GDG").document("W3") #指向目標document地址 doc = doc_address.get() #取出地址中的資料 if doc.exists: doc_data = doc.to_dict() history = doc_data.get("record", []) #取出資料中,指定標籤的資料 else: history = [] print(history) ``` 則剛剛送給Firebase的資料就全在```history```這個變數中 ```python= history.append(reply_text) doc_address.set({"record": history}) ``` 我們可以將rely_text插入到history變數中,並且最後對document地址宣告set,把history的資訊推回到Firebase中。 ### 4-2 有了記憶後,結合Gemini吧! 初始化設定Gemini ```python= # Gemini 初始化 ###################################################### genai.configure(api_key=os.getenv("GEMINI_API_KEY")) model = genai.GenerativeModel("gemini-1.5-pro") ###################################################### ``` 請把當前格子的程式碼改成這樣 ```python= # 存到 Firestore(範例結構: GDG/W3_memory/records/{儲存訊息}) ################################################################### doc_address = db.collection("GDG").document("W3_memory") doc = doc_address.get() if doc.exists: doc_data = doc.to_dict() history = doc_data.get("record", []) else: history = [] print(history) gemini_response = model.generate_content(f"之前談話歷史為{history},請回答{user_message}") gemini_response_text = gemini_response.text.strip() line_bot_api.reply_message(reply_token, TextSendMessage(text=gemini_response_text)) history.append({ "user": user_message, "gemini_reply": gemini_response_text }) doc_address.set({"record": history}) ################################################################### ``` 上述程式碼的目標 : 將Gemini的回應與user的輸入包裝再一起,並且將其傳送到指定地址的document中。 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/r1-OP9uygx.png" style="width: 50%; border: 2px solid black; padding: 5px;" /> </div> 只要有了資料庫,並且調用資料庫資料給Gemini看,就可以使"每次對答"都能夠記住之前說過甚麼。 ## 第5步 : 當你開發到一定階段後 >[!Warning]接下來的步驟 >因為Render實在有點難理解我在想甚麼,所以如果我們要將作品推到Render上,有一個下下策,需要一定轉換 請將你原先的Firebase初始化改成: ```python= # === 初始化 Firebase === firebase_cred_str = os.getenv("FIREBASE_KEY") #放在遠端得環境變數中 firebase_initialized = False if firebase_cred_str: cred_dict = json.loads(firebase_cred_str) # 將 JSON 字串轉回 dict cred = credentials.Certificate(cred_dict) initialize_app(cred) db = firestore.client() firebase_initialized = True else: raise ValueError("未設定 FIREBASE_CREDENTIAL_JSON") ######################################################### ``` 並且驅動在Github上面的程式碼`change.py`,他會將你的Firebase憑證轉格式,你應該會得到一條結果 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/SJPrJpegle.png" style="width: 100%; border: 2px solid black; padding: 5px;" /> </div> 請把```FIREBASE_KEY=```後面的所有東西複製下來 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/r1s5Jpxexe.png" style="width: 100%; border: 2px solid black; padding: 5px;" /> </div> 把剛剛那一串打進```ENVIRONMENT->FIREBASE_KEY```當中,正常來說就可以在雲端上跑了。 ## 第6步 : 一些開發Linebot可以有的小知識 ### 取得使用者 ID(userId)做身份追蹤 ```python= user_id = event.source.user_id ``` 在def handle_message(event),除了可以提取詢問的內容,也可以提取"詢問人的userID",可以運來做身分認證。 ### 取得使用者的基本資料 ```python= profile = line_bot_api.get_profile(user_id) name = profile.display_name ``` 可以利用user_id提取出該使用者的部分資訊,例如姓名。 (---有找到新的資料就會繼續更新---)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully