2023年11月26日 星期日

使用DALL-E3在程式碼中動態生成圖片

圖片

我依稀還記得AI的上一波潮流,大概是在2016年前後,各種基於類神經網路模型的應用開始市場化。但當時,還沒有到現在這種遍地開花的程度。

自從去年2023年11月,ChatGPT出現之後,坊間對生成式AI的各種想像開始變成了各種應用,圖像生成當然也是其中之一。

如今,透過雲端的API,使用程式碼來動態產生圖片,已經是人人都能夠做的事情。OpenAI除了提供文字的生成,也提供了圖像的生成,採用的是DALL-E技術,最新的更新是DALL-E3,加入了類似於 ChatGPT 的 AI 聊天機器人技術來幫助完善圖像生成的提示,也因為這樣,你只需要透過自然語言,以形容的方式,甚至只需要打個關鍵字,就可以讓AI輕易的為你繪製出想要的圖片,支援不同的大小(1024x1024, 1792x1024, or 1024x1792)與風格。​

熟悉REST API使用的開發人員,可以輕易地透過底下這樣的方式,來呼叫API,產生所需的圖片(底下是透過postman工具呼叫API的擷圖):
圖片

如同上面API呼叫中的提示,我們要生成 “麥當勞美味的漢堡” ,出現的圖片如下:
圖片

完整的HTTP/1.1 呼叫為:

POST /v1/images/generations 
Host: api.openai.com
Authorization: Bearer ______API_KEY______________
{
  "model": "dall-e-3",
  "prompt": "麥當勞美味的漢堡" , "n": 1,
  "size": "1792x1024"
}

你會發現,其實呼叫方式相當簡單,endpoint 是 https://api.openai.com/v1/images/generations ,只需要在http Header中提供 API Key 即可呼叫,API Key的建立方式在這裡。不過當然,好的服務是要付費的,OpenAI 關於DALL-E的費用在這裡

使用C#呼叫API的程式碼如下:

using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        // 設定API的端點和授權金鑰
        string endpoint = "https://api.openai.com/v1/images/generations";
        string apiKey = "_____YOUR_API_KEY_HERE_____";

        // 創建HttpClient並設定授權頭部
        using (HttpClient client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");

            // 創建請求的內容
            string jsonContent = @"
            {
                ""model"": ""dall-e-3"",
                ""prompt"": ""機器人、繪畫、人工智慧"",
                ""n"": 1,
                ""size"": ""1792x1024""
            }";
            StringContent content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

            // 發送POST請求
            HttpResponseMessage response = await client.PostAsync(endpoint, content);

            // 檢查響應
            if (response.IsSuccessStatusCode)
            {
                string responseBody = await response.Content.ReadAsStringAsync();
                Console.WriteLine("成功接收到回應!");
                Console.WriteLine(responseBody);
            }
            else
            {
                Console.WriteLine($"錯誤:{response.StatusCode}");
            }
        }
    }
}

想當然的,程式碼不是我寫的,是ChatGPT寫的。

需要的話,請自行下載:
git clone https://github.com/isdaviddong/ex_OpenAI_dalle3_basic.git

Python可以直接使用SDK

import webbrowser
from openai import OpenAI

# 使用瀏覽器開啟圖片
# url (str): 圖片的網址
def open_image_in_browser(url):
    webbrowser.open(url)

# 建立 OpenAI 的 client
client = OpenAI(api_key="_________👉YOUR_API_KEY___________")

# 產生圖片
response = client.images.generate(
    model="dall-e-3",
    prompt="麥當勞的美味漢堡",
    size="1024x1024",
    n=1,
)

# 取得圖片的網址
image_url = response.data[0].url
# 使用瀏覽器開啟圖片
open_image_in_browser(image_url)

另外,生成圖片時候的 prompt 與 Web的ChatGPT完全相同,因此,你可以參考底下這個網頁的說明:
https://medium.com/dean-lin/dall-e-3-必學的-8-個技巧-輕鬆上手-ai-繪圖-21f359c83004

相信對生成想要的圖片很有幫助。


相關課程:
https://www.studyhost.tw/NewCourses/LineBot

2023年11月25日 星期六

AI to AI Communication

圖片
聚餐中,朋友屢屢接到電話,聽了一兩秒,又直接掛掉電話。

『怎麼了嗎?』我問。

『沒有,都是廣告』朋友無奈的說『現在會打手機給我的,要麼是推銷,要麼是民調,不然就是問我要不要借錢,剩下的十之八九都是詐騙。』

我說:『那你不要接就好啦。』

朋友回答:『沒辦法,怕是潛在客戶打來的,沒接到就少了一個案子的機會。現在,那個 who’s call 的 app 辨識率愈來愈低,很多電話號碼也根本沒紀錄,不接不行啊…』

『最可惡的是,現在很多打來的都是機器人!!! 聲音還很好聽,你聽了半天,它還會問你問題,你被騙回答後,才發現電話另一頭其實根本不是人』朋友忿忿的說。

『哈哈哈哈,你現在才知道喔?』我笑著說。

『我之前不是早說了嗎,如今的 類神經網路 AI ,不僅可以聽懂你說的語音,即時辨識語意,還能直接動態產生擬真的悅耳人聲語音回覆你,這年頭,這些技術都早已不是問題,更何況現在還有 ChatGPT 加持,眼見都不能為憑了,更別說只是遠端的聲音? 』

『真沒有辦法可以反制嗎? 這樣好煩哦😫』朋友問。

我說:『其實,我最近有個 Idea,搞不好有用。』

『願聞其詳?』朋友看著我。

我覺得,可以作一個手機 app,然後你有電話來的時候,它就自動幫你接聽,用 AI 語音識別來辨識對方是誰,並且開始跟對方對話,詢問對方的意圖。如果是詐騙、民調、推銷、貸款、投資…就陪對方聊天,聊到天昏地暗,讓對方的行銷(詐騙)成本提高,如此一來,就可以逐漸減少這類煩人的機器人電話。

朋友說:『你是說,我們在手機上作一個聊天機器人app,跟對方的聊天機器人聊天,來反制對方的聊天機器人?』『沒錯。』我回答

『咦? 這有點個人語音秘書的概念吼?』

『對,而且現在這很便宜,可以用極低的成本開發出來。』

『虧你想得出來,那以後就都是AI在講話,AI在寫信,人類要幹嘛?』

『當然是吃吃喝喝、快快樂樂的過一生啦😁』我驕傲地說。

朋友不置可否的笑了笑。

這時,手機又響了起來,上面沒有來電者姓名。

『接不接?』我笑著問他。

『接啊,不然怎麼辦,等你的 app 問世嗎?』朋友無奈的回答,拿起手機『喂』了一聲。

我不忍繼續看下去,逕自走向廁所的方向。

『希望他也能夠跟機器人聊的愉快』我心裡這樣想著。

2023年11月11日 星期六

(無須程式碼)三分鐘建立出自己的GPT請假助手

OpenAI DevDay 最驚豔的展示之一,就是現在人人都可以設計自己的GPT了。
(成果展示影片請參考底下)

不用寫程式,只需要跟ChatGPT以對談的方式,ChatGPT就可以自動幫你做出客製化的GPT,給你的公司、客戶、甚至上架給所有人使用。

只要你有ChatGPT帳號,即可開始建立:
圖片

ChatGPT會問你想建立什麼功能的GPT,用對談的方式,一步一步引導你做出自己客製化版本的GPT,還可以即時預覽:
圖片

你可以用對談的方式(當然也可以上傳文件),讓ChatGPT知道請假規則:
圖片

對談之中,不知不覺的,你的客製化GPT已經完成,你可以選擇公開給全世界所有人,或是只給自己的好友或企業使用:
圖片

可預見的未來,將能更進一步的,串接企業系統的API,與自己企業內的ERP、CRM、HR系統整合。

半年前,我在一次受訪中曾說,ChatGPT的出現,將會改寫資訊系統的UI發展方向,如同電影Star Trek中,以自然語言語音控制電腦實現你想要完成的任何功能,現在已經近在眼前。

做完之後,用戶就可以透過客製化GPT以自然語言的對話方式請假了:

改變真的很大,未來將會發生什麼變化,就留給大家自己想像了…

2023年11月8日 星期三

使用 JSON Mode 讓 OpenAI API 乖乖回傳 JSON

圖片

有在使用 ChatGPT(OpenAI API)開發的Developers 一定知道,對於開發人員來說,使用OpenAI API有一個重要的技巧,就是要求 API 回傳JSON格式的物件。

這樣的 Prompt 非常好用,因為 ChatGPT 最強的功能可能不是回答正確的答案,但對於理解用戶說的自然語言,絕對可以說是所向披靡、無人能及。

如果在程式碼中,能夠要求OpenAI API固定的回傳JSON格式,這樣我們就可以輕鬆的Parsing回傳結果。然而,過去的OpenAI API,就算你的 Prompt 寫的再好,在幾十次的呼叫當中,總是會有一兩次回傳給你的不是精準的JSON格式,而是帶有描述性的字串,這可能會讓接收的程式立刻崩潰,除非你在程式碼中額外做一些判斷,然後重新呼叫API,retry到接收到正確的JSON格式為止。但顯然,這樣的結構設計會讓程式顯得有點傻。

如果OpenAI API能乖乖的回傳 JSON 不就好了嗎?
恩~ 恩~ OpenAI DevDay 之後,這件事情實現了。

現在你可以在呼叫 Chat API 的時候,加上底下的參數:

"response_format"  :  {"type":  "json_object"  }

這會讓回傳的結果一律變成 JSON 形式。
圖片
這指令必須搭配新的 Model 👉gpt-4-1106-preview 或 gpt-3.5-turbo-1106

JSON Mode可以確保你拿到的一定是一個可以解析(Parsing)的 JSON 字串,這使得你 parsing JSON 的時候,不會得到 null,開發人員終於可以不再碰到因為 ChatGPT 的回傳不確定性,所可能帶來的程式崩潰問題。

我自己覺得,OpenAI DevDay中新推出的JSON Mode這個小功能反而是對開發人員最大的幫助。

2023年11月6日 星期一

在自己的系統中實現手機二階段驗證

圖片
現在的應用程式登入,特別是 Microsoft, Google, Facebook等大廠的網站SSO登入,常常設計有二階段驗證(2FA),而其中手機App二階段驗證是最常用的模式。主要是因為簡單、迅速、免費,對於用戶、開發人員、網站本身,都是一個很好的選擇。

這種透過手機App實現的二階段驗證,採用的常是一種稱為TOTP(Time-based One Time Password)的技術。簡單的說就是,用戶以先以正確的帳號密碼登入之後,必要時(或每次)再跳出一個驗證視窗,讓用戶輸入另一組隨機產生的N位數密碼,而該密碼會自動出現在你的手機(APP)上,且只能使用一次並有時間限制。

如此一來,即便用戶的帳號密碼不慎外洩,駭客也必須要有用戶的手機,才能登入或執行進階的功能。當然,如果每次都要這樣驗證,用戶肯定會覺得麻煩,所以這類的驗證,往往不會在每次登入時都進行,而是在底下幾種情境下被觸發:

  1. 用戶在不尋常的情境下(地區、IP、時間)登入
  2. 用戶要進行進階的行為(例如變更密碼)

觸發的時機或演算法因系統特性不同而異,但2FA做法的原理則大致相同,這一篇,我們就來看如何實現2FA。

概念

How to use the Authy API with Google Authenticator (or any compatible  authenticator app)
上圖是 Twilio 網站的 TOTP示意圖,現在有很多業者提供 Authenticator App來實現這個功能,我自己喜歡 Twilio 的 Authy Authenticator, 你可以從底下位置下載:
https://authy.com/download/

使用 Authenticator App 實現2FA 的典型流程如下:

  1. 網站針對已登入的用戶產生一個唯一的key值,並以這個Key值產生URL,進而生成QR Code
  2. 讓用戶以任何一款Authenticator App掃描該 QR Code,即可在該App上登記註冊。
  3. 掃描好QR Code完成註冊後,一般會先做一次六位數密碼驗證,以便於確認用戶有正確完成掃描註冊。
  4. 未來,任何需要二階段驗證的時機,網站後台都可以呼叫API產生六位數密碼,並讓用戶在手機上檢視由App產生的六位數密碼,若兩者相同,即可確認用戶身分正確無誤。

實作

程式碼其實一點都不難,而且有現成的NuGet套件可以使用,我整理好的 source code 這邊:
https://github.com/isdaviddong/TOTP2FA.git

其中,針對已登入的用戶,產生唯一一個key值的程式碼如下:

using OtpNet;

Console.WriteLine($"\n ------------生成QR Code---------------");
string label = "Label Name";
string issuer = "Your App Name";
string accountName = "user@example.com";
byte[] secretKey = KeyGeneration.GenerateRandomKey();
string keyAsBase32String = Base32Encoding.ToString(secretKey);
Console.WriteLine($"\n\n已自動生成 secretKey: '{keyAsBase32String}' ,應妥善保存於資料庫中  ");

我們使用了 OtpNet 套件,上面的 secretKey ,是OtpNet套件自動幫我們產生的,當然你也可以自己產生。請將該 secretKey 跟用戶名稱一齊保存起來即可。

未來,只要用該 secretKey 產生的六位數一次性密碼,就會跟用戶手機上產生的密碼同步。

要具體實現這個,你得先讓用戶掃描QR Code,可以透過底下這段程式碼,建立生成QR Code所需要的URL:

var totp = new Totp(secretKey);
string provisioningUri = $"otpauth://totp/{Uri.EscapeDataString(label)}:{accountName}?secret={keyAsBase32String}&issuer={Uri.EscapeDataString(issuer)}";
Console.Write($"使用 secretKey 產生的 URL : \n{provisioningUri}");
Console.WriteLine($"\n\n請掃描此 URL 產生的 QR Code... ");

上面這個以 otpauth://totp/ 開頭的URL,其實就是 QR Code,你只需要用坊間的 QR Code生成套件,即可針對該URL產生 QR Code。

用戶以手機上安裝好的Authenticator App掃描該QR Code之後,即可為你的網站在手機應用程式上,註冊出一個一次性密碼產生器。

一般來說,我們會先讓用戶完成註冊,隨時用app產生的六位數密碼進行第一次驗證,以確保用戶操作正確。

這部分你可以用底下這段Code來實現:

bool result = false;
while (result != true)
{
    long TimeStep = 0;
    Console.Write($"\n 輸入六位數一次性密碼 : ");
    var Inputkey = Console.ReadLine();
    result = totp.VerifyTotp(Inputkey, out TimeStep);
    Console.Write($"驗證結果 : {result}");
}
Console.WriteLine($"\n 當驗證結果為 true, 未來,即可隨時使用同樣的 secretKey '{keyAsBase32String}' 建立totp物件,進行身分驗證 ");

通過上面這段 code 所產生的一次性密碼,如果符合用戶手機上app所產生的,那也就意味著,用戶成功的對齊(註冊)了我們的App。

這時你就可以把該用戶的email和secretKey 儲存起來,未來,任何需要驗證時候,你只需要用底下這段code,即可產生一組跟用戶手機app上所產生的一次性密碼相同的六位數密碼:

result = false;
Console.WriteLine($"\n ------------開始驗證---------------");
while (result != true)
{
    long TimeStep = 0;
    var totp2 = new Totp(secretKey);
    Console.Write($"\n 輸入六位數一次性密碼 : ");
    var Inputkey = Console.ReadLine();
    result = totp2.VerifyTotp(Inputkey, out TimeStep);
    Console.Write($"驗證結果 : {result}");
}

如此一來,即可驗證當前使用系統的用戶,確實擁有該用戶的手機(也就是說他是用戶本人)。這個功能,就程式碼來說,其實是非常簡單的。

2023年11月2日 星期四

在APIM中自動使用Jwt Token統一進行驗證

圖片

Azure API Management (APIM) 是 Microsoft Azure 服務的一部分,主要功能在協助組織建立、發佈、維護、監控和保護 API。
圖片
其主要功能包含:

  • API Gateway
  • 限流和配額
  • 分析和監控
  • 保護 API
  • 現有服務的代理和包裝 …

使用 Azure APIM 可以幫助組織提供統一的 API Gateway、提升 API 管理與發佈、更確保 API 的安全和可靠性。因此,在最近幾年許多企業開始想走微服務或是API first的架構下,常常做為API的對外閘道。

這樣做有一個好處,拿保護API做為例子,透過APIM,你只需要透過設定,就可以讓Gateway 後面的所有API都支援 JWT token驗證,你就無需在每隻API的程式碼裡面,去做token驗證的動作。

這一篇,我們就來實踐這個例子。

使用 Policy

我們做好了一組測試API,呼叫的網址是 https://testapim20231030.azure-api.net/conference/speakers ,這是APIM的雲端位置,它保護了我們原始的API Endpoint,這也是閘道器基本的功能和行為。

你會發現,預設狀況下我們透過postman在呼叫這組API的時候,是無需驗證帳號密碼的:
圖片

假設,我們希望讓 APIs 都受到JWT token驗證的保護,那只需要在 InBound Policy 這邊做設定:
圖片

加入底下這條 policy:

<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized">
    <issuer-signing-keys>
        <key>123456781234567812345678</key>
    </issuer-signing-keys>
    <required-claims>
        <claim name="admin" match="any">
            <value>true</value>
        </claim>
    </required-claims>
</validate-jwt>

其中的 key 是 JWT token 的 金鑰,如此設定之後,未來沒有帶上 JWT token,將會無法呼叫(收到401錯誤):
圖片

直到我們給了適當的 JWT token:
圖片
才能夠正確呼叫。

這個JWT token,必須採用同樣的key生成,並且必須內含 admin=ture 的 Claim 資訊(對Claim不熟請參考筆者這一篇文章),因為我們在 XML 的 policy 中,指定要驗證 jwt token 中的 admin 資訊:

    <required-claims>
        <claim name="admin" match="any">
            <value>true</value>
        </claim>
    </required-claims>

所以,當呼叫該API時,必須帶上jwt token,且其中必須包含 admin為true的設定,這樣才能夠通過。

底下是生成該 jwt token 的基本參數:
圖片

如此一來,我們在production階段,可以輕易地統一針對被包裹的API置換或設定JWT token 的驗證條件與規則,而開發階段則完全不需要去管這些瑣事。這樣不僅僅方便開發測試,也便於在production階段,針對不同單位(團隊)所開發出的API做統一的權限與驗證管理,對微服務的搭建有著莫大的好處。

2023年10月30日 星期一

輕鬆建立具有 ChatGPT AI能力的LINE Bot

ChatGPT 也紅了好一陣子,大部分開發人員應該也知道,如果要把ChatGPT的能力整合到自己的專案當中,可以透過 Open AI 所提供的API(或是微軟提供的Azure OpenAI API)。

我們開發LINE Bot也是,想做一個具有ChatGPT能力的LINE Bot非常簡單。如果你是C#開發人員,甚至可以直接用套件和範本來完成。
圖片

你可以先用 .net 6 以上的環境建立 WebAPI專案:

md testgptbot
cd testgptbot
dotnet new webapi

完成後,請一併執行 LineBotSDK和LineWebHook範本的安裝:

dotnet add package linebotsdk
dotnet new install isRock.Template.LineWebHook 
dotnet new linewebhook

執行後你會看到底下畫面:
圖片

這時開啟專案,會看到這些範本內容,主要是LineBotChatGPTWebHookController 這隻:
圖片

這隻是寫好的 LINE Bot 範本,同時支援 OpenAI API 和 微軟的Azure OpenAI API。如果您熟悉LINE Bot的開發,只需要把25行的Channel Access Token換掉,順便把 20 行的 Admin User ID換掉(這是處理發生例外的訊息用的),這樣主程式就完成了。Channel Access Token和Admin User ID這些資訊你可以從LINE Developers Console(https://developers.line.biz/console)找到:
圖片

為了讓這個 LINE Bot 可以支援 OpenAI API,我們把需要一個 OpenAI的API Key,這個Key可以從OpenAI的開發人員後台(API keys - OpenAI API)看到:
圖片

有了這些資訊之後,只需要把剛才LineBotChatGPTWebHookController 這隻程式碼中的 117 行調整成 return ChatGPT.CallOpenAIChatAPI(…),並填入剛才取得的key:
圖片

將其運行起來之後,你就可以跟這隻 LINE Bot互動了:
圖片

你會發現,有了 ChatGPT加持,它現在可以輕易的回答任何問題。但由於我們在 prompt 中,設定這隻 LINE Bot是 “專業的客戶服務人員” ,因此針對我們提的以巴問題,它的回答顯得婉轉又不失禮貌。

好啦,建立一支支援 AI 的 LINE Bot就是這麼簡單。🥂

熱門文章