我們試著使用Golang和GPT API,自動根據輸入的主題將部落格發布到WordPress上
首先
最近,OpenAI的chatGPT引起了很大的关注,它是一种能够进行对话的人工智能。我想利用它自动在WordPress上发布文章,并打算用我正在学习的Golang语言来制作它。
鉴于GPT API的文档主要是以Python为基础,所以一般情况下使用Python可能更常见。
顺便提一句,关于GPT API的使用方法,我已经在我个人的博客上做了介绍。
另外,所有代码都存放在这里。
请按照这个说明进行操作。
GPT API参考文档
WordPress API参考文档
先考虑一个提示。
为了预期的问答回答,请将回答用日语表示,问题用英语表示。这是因为与API费用有关的令牌数量会更多地涉及日语,所以用英语编写问题似乎更好。
首先,为了得到结果,请你用日语回答。
You are a helpful assistant that speaks Japanese
我将其设为角色的系统,这样会话将完全以日语回复。
接下来要求他们做什么以及如何设置条件呢?通过以下方式,让他们考虑博客标题和正文。
#Operation.
Write a blog post for me. Generate a blog title and content for the topic: {topic}.
#conditions
{conditions}
上述中,我們可以輸入博客的主題至「{topic}」,以及輸入博客的字數限制等條件至「{conditions}」,並且使其生效。
目前关于提示符的问题就暂时完成了。
实施
首先建立GPT API的处理。
定义数据类型
type GptRequest struct {
Model string `json:"model"`
Messages []struct {
Role string `json:"role"`
Content string `json:"content"`
} `json:"messages"`
}
type GptResponse struct {
Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
} `json:"usage"`
Choices []struct {
Message struct {
Content string `json:"content"`
} `json:"message"`
} `json:"choices"`
}
在上述中,我们定义了用于访问API的数据类型,虽然可以使用字符串,但将其转换为json作为数据类型更容易理解,并且在golang中,转换json的方法也很简单,因此进行转换。
GptRequest的模型中包含要使用的模型(如gpt-4),Messages则是要问的内容。关于Role,它有system、user和assistant三个角色,system和user在向AI提问时扮演相同的角色,但如果使用GPT-4,则优先将设置在此处的问题应用到这里。
关于assistant,它似乎是用于补充提问内容的相关信息。
访问API
func GetContent(topic string, apiKey string) (string, string, error) {
url := "https://api.openai.com/v1/chat/completions"
prompt := "#Operation.\n Write a blog post for me. Generate a blog title and content for the topic: {topic}.\n#conditions \n {conditions}"
fmt.Println("---------- this prompt create ----------")
conditions := strings.Join(["At least 100 words of text"], "\n")
prompt = strings.ReplaceAll(prompt, "{topic}", topic)
prompt = strings.ReplaceAll(prompt, "{conditions}", conditions)
fmt.Println(prompt)
fmt.Println("---------- prompt end ----------")
payload := &GptRequest{
Model: "gpt-4",
Messages: []struct {
Role string `json:"role"`
Content string `json:"content"`
}{
{
Role: "system",
Content: "You are a helpful assistant that speaks Japanese",
},
{
Role: "user",
Content: prompt,
},
},
}
jsonPayload, err := json.Marshal(payload)
if err != nil {
return "", "", err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
if err != nil {
return "", "", err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", "", err
}
fmt.Println("http status " + resp.Status)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", "", err
}
var gpt4Response GptResponse
err = json.Unmarshal(body, &gpt4Response)
if err != nil {
return "", "", err
}
text := gpt4Response.Choices[0].Message.Content
split := strings.SplitN(text, "\n", 2)
title := split[0]
content := ""
if len(split) > 1 {
content = split[1]
}
fmt.Println("usage PromptTokens =", gpt4Response.Usage.PromptTokens)
fmt.Println("usage CompletionTokens =", gpt4Response.Usage.CompletionTokens)
fmt.Println("usage TotalTokens =", gpt4Response.Usage.TotalTokens)
return title, content, nil
}
在上述的代码中,我们通过指定的主题和API密钥创建一个提示,并将其发送到GPT API进行POST请求,然后将返回的响应的json数据转换为GptResponse类型,然后提取标题和正文并返回。
作为请求,将json数据转换为jsonData, _ := json.Marshal(payload)非常简单,将响应转换为数据类型是json.Unmarshal(body, &gpt4Response)一次完成。
创建WordPress的处理程序。
数据类型的定义
与GPT类似,创建请求和响应的数据类型
type WPRequest struct {
Title string `json:"title"`
Content string `json:"content"`
Status string `json:"status"`
}
type WPResponse struct {
ID int `json:"id"`
}
这次需要的是标题、正文和是否公开。因此,在请求中定义了Title、Content和Status这三个参数,并且在响应中可以获取到所创建文章的ID。
访问API
func PostBlog(title string, content string, siteName string, apiKey string, postUserName string) error {
url := siteName + "/wp-json/wp/v2/posts"
payload := &WPRequest{
Title: title,
Content: content,
Status: "publish",
}
jsonPayload, err := json.Marshal(payload)
if err != nil {
return err
}
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
req.Header.Add("Content-Type", "application/json")
req.SetBasicAuth(postUserName, apiKey)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
fmt.Println("http status " + resp.Status)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
var wpResponse WPResponse
json.Unmarshal(body, &wpResponse)
fmt.Printf("Posted new blog with ID: %d\n", wpResponse.ID)
return nil
}
我們將基於所提供的標題、內容、網站名稱(域名)、API金鑰和作者使用者名稱來發布文章。
我們將進行發布設置,將狀態設為”發布”,以便公開它。
创建main.go文件
创建一个名为main.go的入口文件,通过使用最后创建的函数来实际进行发布。
func main() {
openAIKey := os.Getenv("OPENAI_API_KEY")
siteName := os.Getenv("WORDPRESS_SITE_NAME")
postUserName := os.Getenv("WORDPRESS_USER_NAME")
wordpressKey := os.Getenv("WORDPRESS_API_KEY")
reader := bufio.NewReader(os.Stdin)
fmt.Println("Enter the topic for the blog post:")
topic, _ := reader.ReadString('\n')
fmt.Println("Thank you input topic")
topicLog := fmt.Sprintf("generating blog for gpt [topic = %s\n]", topic)
fmt.Println(topicLog)
title, content, err := openai.GetContent(topic, openAIKey)
fmt.Println("completing generating blog for gpt")
if err != nil {
fmt.Println(err)
return
}
fmt.Println("posting blog")
wordpress.PostBlog(title, content, siteName, wordpressKey, postUserName)
fmt.Println("complete posting blog")
}
在上述代码中,通过使用os.Getenv从环境变量中获取必要的信息,如API密钥和网站名称。然后通过使用reader := bufio.NewReader(os.Stdin)从命令行界面输入的主题信息来创建文章。
执行
我想要使用环境变量,因此我想要创建.env文件并在makefile中执行。
OPENAI_API_KEY=your_openai_api_key_here
WORDPRESS_SITE_NAME=your_wordpress_site_name_here
WORDPRESS_USER_NAME=your_wordpress_user_name_here
WORDPRESS_API_KEY=your_wordpress_api_key_here
include .env
export
.PHONY: build run
build:
go build -o build/auto-blog-wordpress
run: build
./build/auto-blog-wordpress
我将尝试运行上述的make run命令。
make run
go build -o build/auto-blog-wordpress
./build/auto-blog-wordpress
Enter the topic for the blog post:
sample
Thank you input topic
generating blog for gpt topic = sample
---------- the topics ----------
generating blog for gpt [topic = sample
]
---------- end ----------
---------- this prompt create ----------
#Operation.
Write a blog post for me. Generate a blog title and content for the topic: sample
.
#conditions
content is 'sample'
---------- prompt end ----------
http status 200 OK
usage PromptTokens = 50
usage CompletionTokens = 882
usage TotalTokens = 932
completing generating blog for gpt
posting blog
http status 201 Created
Posted new blog with ID: 2152
complete posting blog
我感觉日志有些奇怪,但是已经成功了。
我在WordPress上看到了可以创建相应内容的文章。
然而,由于返回的内容不是HTML,所以在源代码和段落指定等方面仍然有很多工作要做。我希望通过调整提示符和WordPress设置来尽力使文章能够以漂亮的方式发布。