Gemini API 快速入門: 來用 Js 做一個線上聊天吧

Google 的 Gemini 推出了幾個月,雖然我個人覺得能力不及 GPT-4 但是每分鐘免費 60 次呼叫也太大方了吧! 還不趕快來玩一波。今天我們就來使用純 HTML 和 JavaScript 製作一個簡單的線上對話網站來與 Gemini 聊天吧!

真的有夠尷尬

1. 申請金鑰

首先請你到 Google AI Studio 申請金鑰。

Google AI Studio 點選 Create API Key

你可以選擇你已經有的專案或是新建一個專案,然後點選 Create API Key。生成後請記得複製下來。

複製生成的 API KEY

2. 呼叫 Gemini API

Gemini 很貼心有預設做好一些 SDK,但是其實我們只需要一個簡單的 HTTP 請求就可以了。完整的 cookbook 可以在 GitHub 查看。

在我們實際開始製作之前,請讓我先簡單介紹一下 Gemini API 的使用方式。

2.1. 問問題

以下是一個簡單的範例。

1curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=$GOOGLE_API_KEY" \
2    -H 'Content-Type: application/json' \
3    -X POST \
4    -d '{
5      "contents": [{
6        "parts":[{"text": "Give me python code to sort a list."}]
7        }]
8       }'

可以看到我們只需要將問題放在 text 中,然後就可以得到回答了。

 1{
 2  "candidates": [
 3    {
 4      "content": {
 5        "parts": [
 6          {
 7            "text": "```python\n# Example list to be sorted\nlist1 = [5, 3, 1, 2, 4]\n\n# Sort the list in ascending order\nlist1.sort()\n\n# Print the sorted list\nprint(list1)\n```"
 8          }
 9        ],
10        "role": "model"
11      },
12      "finishReason": "STOP",
13      "index": 0,
14      "safetyRatings": [
15        {
16          "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
17          "probability": "NEGLIGIBLE"
18        },
19        {
20          "category": "HARM_CATEGORY_HATE_SPEECH",
21          "probability": "NEGLIGIBLE"
22        },
23        {
24          "category": "HARM_CATEGORY_HARASSMENT",
25          "probability": "NEGLIGIBLE"
26        },
27        {
28          "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
29          "probability": "NEGLIGIBLE"
30        }
31      ]
32    }
33  ],
34  "promptFeedback": {
35    "safetyRatings": [
36      {
37        "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
38        "probability": "NEGLIGIBLE"
39      },
40      {
41        "category": "HARM_CATEGORY_HATE_SPEECH",
42        "probability": "NEGLIGIBLE"
43      },
44      {
45        "category": "HARM_CATEGORY_HARASSMENT",
46        "probability": "NEGLIGIBLE"
47      },
48      {
49        "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
50        "probability": "NEGLIGIBLE"
51      }
52    ]
53  }
54}

雖然很長看起來很可怕,但你只需要記得 data.candidates[0].content.parts[0].text 就是回答了。

2.2 發送圖片

如果你想要發送圖片,只需要稍微修改 body 裡的 Json 就可以了。把圖片轉成 base64 放入即可。以下是一個 body 的範例。

 1{
 2  "contents":[
 3    {
 4      "parts":[
 5        {"text": "This image contains a sketch of a potential product along with some notes. \
 6        Given the product sketch, describe the product as thoroughly as possible based on what you \
 7        see in the image, making sure to note all of the product features. Return output in json format: \
 8        {description: description, features: [feature1, feature2, feature3, etc]}"},
 9        {
10          "inline_data": {
11            "mime_type":"image/jpeg",
12            "data": "'$(base64 -w0 image.jpg)'"
13          }
14        }
15      ]
16    }
17  ]
18}

記得如果你要發送圖片,請記得將模型改成 gemini-pro-vision

1curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${GOOGLE_API_KEY}" \
2        -H 'Content-Type: application/json' \
3        -d @request.json

2.3. 討論串

聊一句不夠過癮嗎?你可以把整個對話過程發給 Gemini

 1curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=$GOOGLE_API_KEY" \
 2    -H 'Content-Type: application/json' \
 3    -X POST \
 4    -d '{
 5      "contents": [
 6        {"role":"user",
 7         "parts":[{
 8           "text": "In one sentence, explain how a computer works to a young child."}]},
 9        {"role": "model",
10         "parts":[{
11           "text": "A computer is like a smart helper that can store information, do math problems, and follow our instructions to make things happen."}]},
12        {"role": "user",
13         "parts":[{
14           "text": "Okay, how about a more detailed explanation to a high schooler?"}]},
15      ]
16    }

2.4. 其他設定

Gemini 還有很多其他的設定,例如 max_tokens 用來設定最大回應字數,temperature 用來設定回應的多樣性等等。你甚至可以使用一些符號來啟動不同的模式。詳細的設定可以參考 Gemini API

3. 製作線上對話網站

我們使用剛才學到的知識來製作一個簡單的線上對話網站,裡面運用了剛才所提到的連續對話功能。直接上完成程式碼,你也可以在這裡貼上你的 API 來直接體驗。

Demo: https://elvismao.com/code/gemini/

  1<!-- @format -->
  2
  3<!DOCTYPE html>
  4<html lang="zh-Hant">
  5    <head>
  6        <meta charset="UTF-8" />
  7        <title>Gemini API 聊天 Demo</title>
  8        <script src="https://cdn.jsdelivr.net/npm/showdown@2.1.0/dist/showdown.min.js
  9"></script>
 10        <style>
 11            * {
 12                padding: 0;
 13                margin: 0;
 14                box-sizing: border-box;
 15            }
 16            body {
 17                font-family: system-ui, -apple-system, BlinkMacSystemFont,
 18                    "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans",
 19                    "Helvetica Neue", sans-serif;
 20                padding: 2rem;
 21                display: flex;
 22                flex-direction: column;
 23                height: 100dvh;
 24            }
 25            #chatHistory {
 26                flex-grow: 1;
 27            }
 28            .inputs {
 29                display: flex;
 30            }
 31            #messageInput {
 32                flex-grow: 1;
 33            }
 34            .inputs > * {
 35                height: 2rem;
 36                padding: 0.5rem;
 37            }
 38            #chatHistory > div {
 39                margin-top: 1rem;
 40            }
 41        </style>
 42    </head>
 43    <body>
 44        <h1>Gemini API 聊天 Demo</h1>
 45<p>毛哥EM製作 <a href="https://emtech.cc/post/gemini-html">教學文章</a></p>
 46        <div id="chatHistory">
 47            <!-- Chat history will appear here -->
 48        </div>
 49        <div class="inputs">
 50            <input type="password" id="apiKey" placeholder="API Key" />
 51            <input
 52                type="text"
 53                id="messageInput"
 54                placeholder="Type your message here..."
 55            />
 56            <button onclick="sendMessage()">Send</button>
 57        </div>
 58        <script>
 59            const converter = new showdown.Converter();
 60            let thread = [];
 61            function sendMessage() {
 62                var apiKey = document.getElementById("apiKey").value;
 63                const message = document.getElementById("messageInput").value;
 64                document.getElementById("chatHistory").innerHTML +=
 65                    "<div><div class='author'>You:</div>" + message + "</div>";
 66                thread.push({
 67                    role: "user",
 68                    parts: [{ text: message }],
 69                });
 70                console.log(apiKey);
 71                fetch(
 72                    "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=" +
 73                        apiKey,
 74                    {
 75                        method: "POST",
 76                        headers: {
 77                            "Content-Type": "application/json",
 78                        },
 79                        body: JSON.stringify({
 80                            contents: thread,
 81                        }),
 82                    }
 83                )
 84                    .then(response => response.json())
 85                    .then(data => {
 86                        const msg = data.candidates[0].content.parts[0].text;
 87                        document.getElementById("chatHistory").innerHTML +=
 88                            "<div><div class='author'>Bot:</div>" +
 89                            converter.makeHtml(msg) +
 90                            "</div>";
 91                        thread.push({
 92                            role: "model",
 93                            parts: [
 94                                {
 95                                    text: msg,
 96                                },
 97                            ],
 98                        });
 99                    })
100                    .catch(error => {
101                        console.error("Error:", error);
102                        document.getElementById("chatHistory").innerHTML +=
103                            "<div><div class='author'>Bot:</div>Error: " +
104                            error +
105                            "</div>";
106                    });
107            }
108        </script>
109    </body>
110</html>

你可以看到我們使用了 fetch 來發送請求,然後將回應顯示在網頁上。其中設定了變數 thread 來保存對話內容,這樣我們就可以連續對話了。由於 Gemini 回覆的格式是 Markdown,所以我們使用了 showdown 來將 Markdown 轉換成 HTML。加上一些簡單的 CSS,我們就完成了一個簡單的線上對話網站。

成果

從這一段冷到發寒的對話中,我們可以看到 Gemini 的回答是有根據前面的對話繼續的。下一步我們來把它跟 Line 聊天機器人串再一起吧!

結語

以上就是使用 Gemini API 製作線上對話網站的方法,希望你能從中學到一些東西。如果你有任何建議或問題都可以在 IG 留言,也歡迎在 InstagramGoogle 新聞追蹤毛哥EM資訊密技