基于最新 ChatGPT API 實現命令行版 ChatGPT
調用 API 需要傳遞 API KEY,我們不希望這個 KEY 硬編碼在代碼中,而是從系統環境變量讀取,從而讓代碼更安全可維護;
調用封裝好的 Go OpenAI 庫與 API 接口進行交互,避免通過 HTTP 協議與原生 API 交互編寫大量重復代碼,讓代碼更簡潔優雅;
(資料圖片僅供參考)
對于第 2 點,可以使用 go-gpt3 庫,這是一個通過 Go 封裝的 OpenAI API 調用庫。
對于第3點,可以使用 glamour 庫,這是一個 Go 語言實現的、能夠在兼容 ANSI 終端基于樣式渲染 Markdown 文本的第三方庫,它是讓命令行更美觀的開源項目 Charm 的一部分。
因為項目很簡單,又是在客戶端本地使用,所以不需要做什么復雜的架構,下面直接進入編碼部分。
代碼編寫
面向 ChatGPT 編程的核心就是把需求盡可能準確全面地轉化為 Prompt 傳遞給 ChatGPT,這里有產品需求(來自業務和產品),也有代碼設計和架構上的需求(來自開發者),然后讓它生成代碼,這是作為一個合格的 Prompt 工程師自我修養的必要組成部分。在《ChatGPT 提示的藝術 —— 編寫清晰有效提示指南(二)》這篇教程中,我已經給大家介紹了編寫清晰有效 Prompt 的原則、做法和技巧,感興趣的可以去看下,這里我先將我的需求轉化為 Prompt 讓 ChatGPT 替我編寫對應的 Go 代碼實現:
代碼優化看起來不錯,基本流程沒問題,但是代碼審核會發現,它現在把輸入的 Prompt 寫死了,并不能動態接收用輸入,而且運行一次后就退出了,這不是 ChatGPT 的問題,而是我們的需求并沒有明確這一點,作為一個完整的需求和程序,需要說明是什么,怎么樣,什么時候開始,什么時候退出。不過細心的同學可能還留意到go-gpt3包引入的時候沒有設置別名,會導致運行時出錯,同時調用的 OpenAI API 接口也不對,最新的 ChatGPT API 接口方法應該是CreateChatCompletion,可能是太新的緣故,ChatGPT 還沒有學習到這里,不過這都屬于 ChatGPT 要優化的點了。以及使用了另一個同名的包,這個也需要明確告知它。細節上還是需要優化,現在我們基于這些要點先來完善我們的 Prompt:package mainimport ("context""fmt""os""strings""github.com/charmbracelet/glamour""github.com/common-nighthawk/go-figure"gpt3 "github.com/sashabaranov/go-gpt3")func main() {// 獲取 OpenAI API KeyapiKey := os.Getenv("OPENAI_API_KEY")if apiKey == "" {fmt.Println("請設置 OPENAI_API_KEY 環境變量")return}// 初始化 Glamour 渲染器renderStyle := glamour.WithEnvironmentConfig()mdRenderer, err := glamour.NewTermRenderer(renderStyle,)if err != nil {fmt.Println("初始化 Markdown 渲染器失敗")return}// 輸出歡迎語(命令行應用啟動界面)myFigure := figure.NewFigure("ChatGPT", "", true)myFigure.Print()fmt.Println("輸入 start 啟動應用,輸入 quit 退出應用")// 創建 ChatGPT 客戶端client := gpt3.NewClient(apiKey)if err != nil {fmt.Printf("創建客戶端失敗: %s\n", err.Error())return}messages := []gpt3.ChatCompletionMessage{{Role: "system",Content: "你是ChatGPT, OpenAI訓練的大型語言模型, 請盡可能簡潔地回答我的問題",},}// 讀取用戶輸入并交互var userInput stringfor {fmt.Scanln(&userInput)if strings.ToLower(userInput) == "start" {fmt.Println("ChatGPT 啟動成功,請輸入您的問題:")} else if strings.ToLower(userInput) == "quit" {fmt.Println("ChatGPT 已退出")return} else if userInput != "" {messages = append(messages, gpt3.ChatCompletionMessage{Role: "user",Content: userInput,},)// 調用 ChatGPT API 接口生成回答resp, err := client.CreateChatCompletion(context.Background(),gpt3.ChatCompletionRequest{Model: gpt3.GPT3Dot5Turbo,Messages: messages,MaxTokens: 1024,Temperature: 0,N: 1,},)if err != nil {fmt.Printf("ChatGPT 接口調用失敗: %s\n", err.Error())continue}// 格式化輸出結果output := resp.Choices[0].Message.ContentmdOutput, err := mdRenderer.Render(output)if err != nil {fmt.Printf("Markdown 渲染失敗: %s\n", err.Error())continue}fmt.Println(mdOutput)messages = append(messages, gpt3.ChatCompletionMessage{Role: "assistant",Content: output,},)}}}
gpt3 別名和 CreateChatCompletion 方法調用相關的代碼還是需要手動調整,不過這也是我前面說的面向 ChatGPT 編程的原則之一,最后一定要審核 ChatGPT 的代碼,它目前對于最新的知識還是有一定的遲滯性。
代碼細節我就不展開解釋了,有不明白的地方可以參考我在《面向 ChatGPT 編程實現全棧開發的 18 種方法》這篇教程中代碼解釋部分提供的方法自行去基于 ChatGPT 查看。
效果展示最后我們在終端體驗一下這個命令行版 ChatGPT,我這里使用的是 Windows WSL 終端,Windows 終端本身體驗其實不太好,尤其是中文輸入的時候,刪除字符特別費勁,且很容易造成消息變形,如果是 Mac 或者 Ubuntu 終端可能效果會更好一些。首先我們啟動這個應用,如果沒有設置OPENAI_API_KEY這個系統環境變量(運行export OPENAI_API_KEY={你的 OpenAI SECRET KEY}命令設置即可),會提示你設置:終端需要能夠訪問 OpenAI API 才能調用成功,這意味著命令行也要支持科學上網。
好了,這就是我們基于最新 ChatGPT API 實現的命令行版 ChatGPT 應用,因為 ChatGPT API 是前兩天才發布的,所以看起來 ChatGPT 并沒有學習到這個最新的 API 如何調用,存在遲滯性,進而導致編寫的代碼并不能直接滿足需求,需要人為介入去修改,希望未來 ChatGPT 能夠在這一塊上有所進化。
歡迎點贊、關注、分享,更多關于 ChatGPT 的學習實踐探討,請關注這個訂閱號或者點擊閱讀原文了解極客書房最新動態。
相關閱讀
-
基于最新 ChatGPT API 實現命令行版 ChatGPT
引子OpenAI這兩天發布了ChatGPTAPI,基于gpt-3 5-turbo模型,這是... -
一個厲害的小工具,小黑子都在用!
大家好,我是魚皮。不知道各位程序員朋友們有沒有這樣一個煩惱:電... -
Oracle 是偷偷變更自己的收費模式么?|...
之前的一個新聞相信很多人都聽說過,簡單說就是Oracle變更了自己的... -
銀行應用系統日志文件敏感信息脫敏處理...
在銀行開發和介質相關的應用或者智能柜臺操作,需要記錄客戶的操作... -
世界頭條:除了第一句之外都是廢話?
前些天發了篇文章,Oracle是偷偷變更自己的收費模式么?有條評論有... -
通過 Pulsar 源碼徹底解決重復消費問題
背景最近真是和Pulsar杠上了,業務團隊反饋說是線上有個應用消息重...