上回提過 Azure 有提供 OpenAI Service,與 OpenAI API 相比,具有 SLA 保證、多區域備援、AD 整合、虛擬網路整合、更符合企業規範... 等特色。而對個人用戶,若手上有 Azure 免費額度(例如:Visual Studio Enterprise 訂閱 150 USD/月 或學生方案 100 USD/年),等於有免費的 ChatGPT4 可以玩,嘗試一些有趣應用。(延伸閱讀:ChatGPT 聊天程式練習 - 使用 .NET + Azure OpenAI API)

若想單純測試及驗證 ChatGPT 的回答,Azure OpenAI Studio 有個 Chat Playground (聊天遊樂場),提供類似 ChatGPT 網頁的對話介面:

但它畢竟是程式開發範例性質,只提供最基本功能,要順手好用還是得自己來。所幸,網路上已有不少 ChatGPT 介面開源專案,不用自己造輪子。我找到這個 - Chatty GPT,純靜態網頁構成的前端介面,不需伺服器端程式,資料則存在 localStorage,檔案丟到 Github Pages、Live Server 或任何靜態檔網站都能跑。Chattyt GPT 沒有太多華麗功能(但需要可自行擴充),介面簡潔操作算順手,最重要最重要的是 - 它使用香草 JavaScript,不依賴 React/Vue/Angular 等前端框架(只有 TailwindCSS 需要編譯產生 min.css),符合我的輕前端理念,便決定以它為基礎改造我想要的個人專屬 ChatGPT 聊天室。

每回摸開源專案總會學到滿滿的新東西,這回也不例外。

Chatty GPT 雖然沒走前端框架,設計上卻十分模組化,靠的是 Web Components,一個存在超過 10 年,各瀏覽器早已內建支援的 HTML 技術。

我做了一個簡單範例,有 userName 屬性決定顯示內容,示範對 click 事件做反應:線上展示

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Web Component</title>
        <style>
            html, body {
                font-family: '微軟正黑體', sans-serif;
            }
            my-component {
                font-size: 20pt;
                cursor: pointer;
                color: dodgerblue;
            }
        </style>
    </head>

<body>

    <div>
        <input type="text" id="name" value="Jeffrey">
        <button onclick="document.getElementById('c').userName=document.getElementById('name').value">
            Chanage
        </button>
    </div>
    <my-component id="c" user-name="World">
    </my-component>    
    <ul>       
    </ul>
    <script>
        class MyComponent extends HTMLElement {
            get userName() {
                return this.getAttribute('user-name');
            }
            set userName(value) {
                this.setAttribute('user-name', value);
                this.render();
            }
            connectedCallback() {
                this.render();
                this.addEventListener('click', () => {
                    document.querySelector('ul').innerHTML += 
                        `<li>Hello, ${this.userName}!</li>`;
                });
            }
            render() {
                this.textContent = `Hello, ${this.userName}!`;
            }
        }
        customElements.define('my-component', MyComponent);
    </script>
</body>

</html>

本次另一項收獲是實際摸到超多人大推,傳說中的 TailwindCSS。

為了擴充增加聊天紀錄刪除鈕,我學會看懂 Web Component 的設計方式,也試著靠 Tailwind 設定 CSS。

改用 TailwindCSS,HTML 的樣式設定會變成像這樣 <chatty-icon name="github" class="text-gray-400 group-hover:text-gray-400 mr-3 h-6 w-6 flex-shrink-0"><img src="del.svg" class="opacity-10 hover:opacity-80 del-btn absolute right-6" alt="delete" />,對於習慣 class="class-name" 再用 Selector 依容器從屬關係管理樣式的開發者來說,看到這裡不免要吐糟「花惹發,怎麼又回到用 style="..." 寫死樣式的原始時代?」 這也是我原本的反應。但經過這次維護經驗,算是約略理解它的設計哲學 - 明確標示樣式簡單直覺,不需要從樣式名稱、元素類別、Attribute 特徵、從屬關係去推敲最後看到的顏色位置大小是怎麼來的,或去調查為什麼結果跟想像的不一樣。class 又長又囉嗦是 Tailwind 的特色,是種取捨。當前前端主流是將網頁拆解成組件或 Web Component,組件的 HTML 範本與樣式直接整合在一起,邏輯集中方便管理,各組件完全獨立不會互相干擾,得到的優勢便會大於成本。但如果簡單兩三頁網頁介面,用上 Tailwind 確實像沒事找事,感受不到好處,這類需求套用 Bootstrap 或其他現成 CSS 框架更方便省事。(延伸閱讀:還在跟複雜的 CSS 的設定奮鬥嗎?用 Tailwind 來幫你實現真正的高效整潔! by Meng-Ying Tsai)

Chatty GPT 沒用到什麼 Tailwind 客製設定,但仍需要編譯,工具會掃瞄 .html, .js 找出用到的樣式宣告(即前面例子中的 mr-3, h-6, w-6, opacity-10...),將其編譯成 global.min.css,裡面只會包含有用到的項目以縮小體積提高使用效率。因此,每次修改 HTML 或 WebComponent 有多引用或移除樣式後,都需跑 npx tailwindcss -m -i ./css/global.css -o ./css/global.min.css 重新編譯。

最後,第一階段成品如下,後端由 OpenAI API 改為 Azure OpenAI Service,並加上聊天項目的刪除鈕。

順便分享一個 ChatGPT 有趣應用 - 產生小圖示 SVG。如上圖,想找個簡單的紅 X 圖示當刪除鈕,上網找到順眼的都需額外授權或姓名標示,最後姑且一試請 ChatGPT 現場生一個,效果還不錯。呵!

我的修改版本已推上 Github,雖然會走這條路的不多,但如果你有 Azure OpenAI Service 想試試草香 JavaScript 做的個人專屬 ChatGPT 聊天室,可以 Clone 一份玩看看。

Chatty GPT is an open source project which provide a pure frontend interface of ChatGPT, I folked it and provide the Azure OpenAI service version.


Comments

# by Ken

受益良多, 感謝分享!!

Post a comment