在本文中,我们将介绍如何使用GoZero框架构建一个简单的服务,来抓取与OpenAI GPT的对话记录并存储。这些对话记录可以包括用户输入、GPT响应以及其他相关信息。我们会展示如何设计接口、保存对话记录并实现基本的错误处理。
## 1. 背景
GoZero是一个高效的微服务框架,基于Go语言构建,旨在简化微服务的开发。本文的目标是通过GoZero框架调用GPT接口并抓取对话记录,同时提供一些常见的错误处理机制和日志记录。
我们假设已经从OpenAI获得了API密钥,并且准备好使用GoZero来访问GPT的对话接口。
## 2. 环境准备
### 2.1 安装GoZero
首先,我们需要安装GoZero框架及相关工具:
```bash
go get -u github.com/zeromicro/go-zero
go get -u github.com/zeromicro/go-zero/tools/goctl
```
### 2.2 获取OpenAI API密钥
请确保你已经在OpenAI平台注册并获得了API密钥。可以通过以下链接生成API密钥:[OpenAI平台](https://platform.openai.com/signup)。
## 3. 项目结构
我们将创建一个简单的GoZero项目,项目结构如下:
```
myservice/
├── config/
│ └── config.yaml
├── handler/
│ └── gpt_handler.go
├── logic/
│ └── gpt_logic.go
├── svc/
│ └── service_context.go
├── types/
│ └── gpt_types.go
├── main.go
└── go.mod
```
### 3.1 配置文件 (`config/config.yaml`)
首先,我们需要一个配置文件来存储GPT API的密钥以及其他配置:```yaml
Name: myservice
Host: 0.0.0.0
Port: 8080
GPT:
ApiKey: "your-openai-api-key"
Endpoint: "https://api.openai.com/v1/completions"
```
### 3.2 定义请求和响应结构 (`types/gpt_types.go`)
为了与OpenAI GPT接口交互,我们需要定义请求和响应的结构。以下是一个简单的结构体定义:```go
package types
// GPTRequest 是发送给OpenAI的请求结构体
type GPTRequest struct {
Model string `json:"model"`
Messages []string `json:"messages"`
}
// GPTResponse 是从OpenAI获取的响应结构体
type GPTResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Choices []struct {
Text string `json:"text"`
} `json:"choices"`
}
// HistoryRecord 用于存储对话记录
type HistoryRecord struct {
ID string `json:"id"`
UserInput string `json:"user_input"`
GPTResponse string `json:"gpt_response"`
Timestamp int64 `json:"timestamp"`
}
```
### 3.3 编写逻辑层 (`logic/gpt_logic.go`)
逻辑层负责处理业务逻辑,包括发送请求到OpenAI和保存对话记录。```go
package logic
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
"myservice/types"
"myservice/service/internal/svc"
"myservice/service/internal/config"
"log"
)
type GPTLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGPTLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GPTLogic {
return &GPTLogic{
ctx: ctx,
svcCtx: svcCtx,
}
}
// CallGPT 向OpenAI发送请求并返回结果
func (l *GPTLogic) CallGPT(req *types.GPTRequest) (*types.GPTResponse, error) {
// 构造请求体
url := l.svcCtx.Config.GPT.Endpoint
body, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %v", err)
}
// 创建HTTP请求
httpReq, err := http.NewRequest("POST", url, bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("failed to create HTTP request: %v", err)
}
// 设置请求头
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Authorization", "Bearer "+l.svcCtx.Config.GPT.ApiKey)
// 发送请求
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("failed to send request: %v", err)
}
defer resp.Body.Close()
// 解析响应
var gptResp types.GPTResponse
if err := json.NewDecoder(resp.Body).Decode(&gptResp); err != nil {
return nil, fmt.Errorf("failed to decode response: %v", err)
}
// 记录对话
record := types.HistoryRecord{
ID: gptResp.ID,
UserInput: req.Messages[0],
GPTResponse: gptResp.Choices[0].Text,
Timestamp: time.Now().Unix(),
}
l.saveHistory(record)
return &gptResp, nil
}
// saveHistory 将对话记录保存到数据库(示例中简单打印)
func (l *GPTLogic) saveHistory(record types.HistoryRecord) {
// 此处可以改为保存到数据库,例如使用ORM或数据库驱动
log.Printf("Saved conversation record: %+v", record)
}
```
### 3.4 创建服务上下文 (`svc/service_context.go`)
服务上下文用于管理配置和服务实例的生命周期。我们将在其中加载配置文件。```go
package svc
import (
"myservice/service/internal/config"
"github.com/zeromicro/go-zero/zrpc"
)
type ServiceContext struct {
Config config.Config
Zrpc zrpc.Client
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
}
}
```
### 3.5 定义API处理器 (`handler/gpt_handler.go`)
处理HTTP请求,接收来自用户的消息,调用GPT接口并返回响应。```go
package handler
import (
"fmt"
"net/http"
"myservice/types"
"myservice/service/internal/logic"
"myservice/service/internal/svc"
"encoding/json"
"github.com/zeromicro/go-zero/rest"
)
func CallGPTHandler(ctx *svc.ServiceContext) rest.Handler {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GPTRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, fmt.Sprintf("Invalid request: %v", err), http.StatusBadRequest)
return
}
// 调用GPT接口
logic := logic.NewGPTLogic(r.Context(), ctx)
gptResp, err := logic.CallGPT(&req)
if err != nil {
http.Error(w, fmt.Sprintf("Error calling GPT: %v", err), http.StatusInternalServerError)
return
}
// 返回GPT响应
respData := map[string]interface{}{
"response": gptResp.Choices[0].Text,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(respData)
}
}
```
### 3.6 启动服务器 (`main.go`)
最后,我们需要启动HTTP服务器来提供对话记录的API。```go
package main
import (
"fmt"
"log"
"net/http"
"myservice/service/internal/config"
"myservice/service/internal/svc"
"myservice/service/internal/handler"
"github.com/zeromicro/go-zero/rest"
)
func main() {
// 加载配置
c := config.Config{
Name: "myservice",
Host: "0.0.0.0",
Port: 8080,
GPT: config.GPTConfig{ApiKey: "your-openai-api-key", Endpoint: "https://api.openai.com/v1/completions"},
}
ctx := svc.NewServiceContext(c)
// 创建REST服务
server := rest.MustNewServer(c)
defer server.Stop()
// 注册API处理器
server.AddRoute(rest.Route{
Method: http.MethodPost,
Path: "/callgpt",
Handler: handler.CallGPTHandler(ctx),
})
// 启动服务器
log.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
if err := server.Start(); err != nil {
log.Fatal(fmt.Sprintf("Failed to start server: %v", err))
}
}
```
### 3.7 启动服务
运行以下命令来启动服务:
```bash
go run main.go
```
现在,服务已经启动,并且可以接受POST请求。你可以通过以下请求调用GPT并保存对话记录:
```bash
curl -X POST http://localhost:8080/callgpt \
-d '{"model": "text-davinci-003", "messages}'
启动服务
运行main.go
后,服务会启动并监听在8080端口,客户端可以通过HTTP POST请求与GPT进行对话。
总结
该项目展示了如何通过GoZero框架搭建一个简单的微服务,它能够调用OpenAI的GPT接口,并保存每次交互的历史记录。关键流程包括配置管理、API请求处理和对话记录保存,确保服务具有可扩展性和易维护性。